Skip to content

Commit

Permalink
Merge branch 'master' into fix-oraclecloud-function
Browse files Browse the repository at this point in the history
  • Loading branch information
n0tl3ss committed Jul 23, 2024
2 parents 1af3b1c + 98c1740 commit 52ecb4c
Show file tree
Hide file tree
Showing 198 changed files with 5,669 additions and 30 deletions.
8 changes: 8 additions & 0 deletions assets/stylesheets/guide.css
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@
text-align: center;
}

table.left-stripes-even td {
text-align: left;
}

table.left-stripes-even tr:nth-child(even) {
background-color: #f2f2f2;
}

.category a {
color: #FFFFFF;
}
3 changes: 2 additions & 1 deletion buildSrc/src/main/java/io/micronaut/guides/Category.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public enum Category implements Ordered {
GOOGLE_CLOUD_RUN("Google Cloud Run", 34),
ORACLE_CLOUD("Oracle Cloud", 35),
KUBERNETES( "Kubernetes", 36),
SPRING_BOOT_TO_MICRONAUT("Spring Boot to Micronaut Framework", 37);
SPRING_BOOT_TO_MICRONAUT("Spring Boot to Micronaut Framework", 37),
BUILDING_A_REST_API("Building a REST API - Spring Boot to Micronaut Framework", 38);

private final String val;
private final int order;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.micronaut.guides.feature;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.starter.application.ApplicationType;
import io.micronaut.starter.application.generator.GeneratorContext;
import io.micronaut.starter.build.dependencies.Dependency;
import io.micronaut.starter.feature.Feature;
import jakarta.inject.Singleton;

@Singleton
public class SpringBootStarterSecurity implements Feature {
@Override
public @NonNull String getName() {
return "spring-boot-starter-security";
}

@Override
public boolean supports(ApplicationType applicationType) {
return true;
}

@Override
public void apply(GeneratorContext generatorContext) {
addDependencies(generatorContext);
}

private void addDependencies(GeneratorContext generatorContext) {
generatorContext.addDependency(Dependency.builder()
.groupId("org.springframework.boot")
.artifactId("spring-boot-starter-security")
.compile());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.micronaut.guides.feature;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.starter.application.ApplicationType;
import io.micronaut.starter.application.generator.GeneratorContext;
import io.micronaut.starter.build.dependencies.Dependency;
import io.micronaut.starter.feature.Feature;
import jakarta.inject.Singleton;

@Singleton
public class SpringDataJdbc implements Feature {
@Override
public @NonNull String getName() {
return "spring-boot-data-jdbc";
}

@Override
public boolean supports(ApplicationType applicationType) {
return true;
}

@Override
public void apply(GeneratorContext generatorContext) {
addDependencies(generatorContext);
}

private void addDependencies(GeneratorContext generatorContext) {
generatorContext.addDependency(Dependency.builder()
.groupId("org.springframework.data")
.artifactId("spring-data-jdbc")
.compile());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.springframework.boot.test.context.SpringBootTest;

@@SpringBootTest
class @project.getClassName()Test {

@@Test
void contextLoads() {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
common:header-top.adoc[]

== Sample Project

You can link:@sourceDir@.zip[download a sample application] with the code examples in this article.

== Introduction

This guide compares how to power a GET endpoint with a persistence layer in a Micronaut Framework and Spring Boot applications.

The Spring Boot application uses https://spring.io/projects/spring-data[Spring Data] and https://www.h2database.com/html/main.html[H2]. The Micronaut application uses https://micronaut-projects.github.io/micronaut-data/snapshot/guide/[Micronaut Data] and H2.

This guide is the third tutorial of https://guides.micronaut.io/latest/tag-building_a_rest_api.html[Building a Rest API] - a series of tutorials comparing how to develop a REST API with Micronaut Framework and Spring Boot.

Micronaut Data is a database access toolkit that uses Ahead of Time (AoT) compilation to pre-compute queries for repository interfaces that are then executed by a thin, lightweight runtime layer.

=== Micronaut Data vs Spring Data

Micronaut Data improves on Spring Data in the following ways:

* **No runtime model** - Spring Data maintains a runtime metamodel that uses reflection to model relationships between entities. This model consumes significant memory and memory requirements grow as your application size grows. The problem is worse when combined with Hibernate which maintains its own metamodel as you end up with duplicate meta-models.

* **No query translation** - Spring Data uses regular expressions and pattern matching in combination with runtime generated proxies to translate a method definition on a Java interface into a query at runtime. No such runtime translation exists in Micronaut Data and this work is carried out by the Micronaut compiler at compilation time.

* **No Reflection or Runtime Proxies** - Micronaut Data uses no reflection or runtime proxies, resulting in better performance, smaller stack traces and reduced memory consumption due to a complete lack of reflection caches (Note that the backing implementation, for example Hibernate, may use reflection).

* **Type Safety** - Micronaut Data will actively check at compile time that a repository method can be implemented and fail compilation if it cannot.

== Dependencies

=== Spring Boot Data and H2

To use Spring Data JDBC and H2 add the following dependencies:

:dependencies:

dependency:spring-data-jdbc[groupId=org.springframework.data]
dependency:h2[groupId=com.h2database,scope=runtimeOnly]

:dependencies:

=== Micronaut Data and H2

To use Micronaut Data JDBC and H2 add the following dependencies:

:dependencies:

dependency:micronaut-data-processor[groupId=io.micronaut.data,scope=annotationProcessor]
dependency:micronaut-data-jdbc[groupId=io.micronaut.data]
dependency:h2[groupId=com.h2database,scope=runtimeOnly]

:dependencies:

Please note the addition of the `micronaut-data-processor` in the annotation processor classpath. Micronaut Data does a lot of work at compilation, which leads to applications with better performance and a reduced memory consumption.

== Entities

We modified the `SaasSubscription` Java Record. We use it as a persistence entity.

=== Spring Boot

For Spring Data, we added the `@Id` annotation.

source:SaasSubscription[app=springboot]

=== Micronaut

For Micronaut Framework, the entity is annotated with `@MappedEntity`.

source:SaasSubscription[app=micronautframework]

callout:serdeable[1]
callout:mapped-entity[2]
callout:mapped-entity-id[3]

== SQL

https://docs.spring.io/spring-boot/docs/2.1.x/reference/html/howto-database-initialization.html#howto-initialize-a-database-using-spring-jdbc[Spring Boot loads SQL from the standard root classpath locations: `schema.sql` and `data.sql`]. Micronaut Framework recommends you manage your database schema with https://micronaut-projects.github.io/micronaut-liquibase/snapshot/guide[Liquibase] or https://micronaut-projects.github.io/micronaut-flyway/snapshot/guide[Flyway].
However, to keep applications as close as possible, we will create the database schema with an SQL file in the Micronaut application. https://micronaut-projects.github.io/micronaut-test/4.3.0/guide/#sql[Micronaut Test supports loading SQL before tests] seamlessly.
To keep both apps as close as possible,

We will use two SQL files in the tests:

- `src/main/resources/schema.sql`.
- `src/main/resources/data.sql`.

=== SQL Schema

testResource:schema.sql[app=micronautframework]

=== Sample Data

testResource:data.sql[app=micronautframework]

== Repository

Both Micronaut Data and Spring Data enable developers to use the repository pattern. You write an interface and the framework provides the implementation.

=== Spring Boot Repository

source:SaasSubscriptionRepository[app=springboot]

=== Micronaut Repository

Because Micronaut Data works at build-time, you have to specify the dialect.

source:SaasSubscriptionRepository[app=micronautframework]

callout:jdbcrepository[1]
callout:crudrepository[2]

== Controller

We modified the controller we wrote in the previous tutorial to inject the repository. We use constructor injection in both applications.

=== Spring Boot Controller

source:SaasSubscriptionController[app=springboot]

callout:spring-boot-rest-controller[1]
callout:spring-boot-request-mapping[2]
callout:spring-boot-get-mapping[number=3,arg0=findById,arg1=/subscriptions/{id}]
callout:spring-boot-path-variable[number=4]

=== Micronaut Controller

source:SaasSubscriptionController[app=micronautframework]

callout:controller[number=1,arg0=/subscriptions]
callout:get[number=2,arg0=findById,arg1=/subscriptions/{id}]
callout:pathvariable[3]
callout:http-response[4]


== Tests

common:assertj-and-json-path.adoc[]

=== Micronaut Test

The Spring boot tests are identical to those in the previous tutorial. In the Micronaut Test, we need to annotate the test with `@Sql` to load the SQL files before the tests.

test:SaasSubscriptionControllerGetTest[app=micronautframework]

callout:micronaut-test-sql[1]
callout:micronaut-test[2]
callout:http-client[3]
callout:http-client-response-exception[4]

== Conclusion

Adding a persistence layer is easy in both frameworks, and the API is almost identical. However, Micronaut Data's compile-time/reflection-free approach results in better performance, smaller stack traces, and reduced memory consumption.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"title": "3. Data - Spring Boot vs Micronaut Framework - Building a Rest API",
"intro": "This guide compares how to add Spring Data or Micronaut Data to power a GET endpoint in both Micronaut and Spring Boot applications.",
"authors": ["Sergio del Amo"],
"tags": ["spring-boot"],
"categories": ["Spring Boot to Micronaut Framework", "Building a REST API - Spring Boot to Micronaut Framework"],
"publicationDate": "2024-04-24",
"languages": ["java"],
"buildTools": ["gradle"],
"apps": [
{
"framework": "Spring Boot",
"name": "springboot",
"features": ["spring-boot-starter-web", "h2", "spring-boot-data-jdbc"]
},
{
"name": "micronautframework",
"features": ["json-path", "assertj", "data-jdbc"]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package example.micronaut;

import io.micronaut.serde.annotation.Serdeable;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;

@Serdeable // <1>
@MappedEntity // <2>
record SaasSubscription(@Id Long id, // <3>
String name,
Integer cents) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.micronaut;

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;

@Controller("/subscriptions") // <1>
class SaasSubscriptionController {

private final SaasSubscriptionRepository repository;

SaasSubscriptionController(SaasSubscriptionRepository repository) {
this.repository = repository;
}

@Get("/{id}") // <2>
HttpResponse<SaasSubscription> findById(@PathVariable Long id) { // <3>
return repository.findById(id)
.map(HttpResponse::ok)
.orElseGet(HttpResponse::notFound); // <4>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.micronaut;

import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.CrudRepository;

@JdbcRepository(dialect = Dialect.H2) // <1>
interface SaasSubscriptionRepository extends CrudRepository<SaasSubscription, Long> { // <2>
}
Loading

0 comments on commit 52ecb4c

Please sign in to comment.