Skip to content

Commit

Permalink
Migration to Micronaut 4 (#357)
Browse files Browse the repository at this point in the history
Co-authored-by: Tim Yates <tim.yates@gmail.com>
  • Loading branch information
dstepanov and timyates committed Nov 10, 2022
1 parent bbea955 commit f24f3a8
Show file tree
Hide file tree
Showing 47 changed files with 791 additions and 1,216 deletions.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,3 @@ configurations.all {
.using(module("org.apache.groovy:groovy:4.0.6"))
}
}

dependencies {
testRuntimeOnly mn.snakeyaml
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
plugins {
id 'io.micronaut.build.internal.servlet.module'
}

dependencies {
annotationProcessor mn.micronaut.graal

api project(":servlet-engine")
api mn.micronaut.http.server

compileOnly mn.graal

testAnnotationProcessor mn.micronaut.inject.java

testImplementation mn.snakeyaml
testImplementation mn.micronaut.http.client
testImplementation mn.micronaut.session
testImplementation mn.micronaut.reactor
testImplementation (mn.micronaut.security) {
version {
strictly '4.0.0-SNAPSHOT'
}
}
testImplementation mn.micronaut.management
testImplementation mn.groovy.json
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
plugins {
id 'io.micronaut.build.internal.servlet.base'
id 'io.micronaut.build.internal.module'
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
projectVersion=4.0.0-SNAPSHOT
projectVersion=3.3.2-SNAPSHOT
projectGroup=io.micronaut.servlet

micronautDocsVersion=2.0.0
Expand Down
19 changes: 2 additions & 17 deletions http-server-jetty/build.gradle
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
plugins {
id "io.micronaut.build.internal.servlet-module"
id 'io.micronaut.build.internal.servlet.implementation'
}

dependencies {
annotationProcessor mn.micronaut.graal

api projects.servletEngine
api mn.micronaut.http.server

implementation(libs.jetty)

testAnnotationProcessor mn.micronaut.inject.java
testImplementation mn.micronaut.management
testImplementation mn.micronaut.http.client
testImplementation mn.micronaut.session
testImplementation(mn.groovy.json)
testImplementation mn.micronaut.reactor
testImplementation mn.micronaut.reactor.http.client

testImplementation(mn.micronaut.security)
implementation libs.jetty
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package io.micronaut.servlet.jetty
import io.micronaut.context.ApplicationContext
import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Requires
import io.micronaut.core.annotation.Introspected
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus
import io.micronaut.http.annotation.*
Expand Down Expand Up @@ -290,6 +291,7 @@ class JettyBlockingCrudSpec extends Specification {
}


@Introspected
static class Book {
Long id
String title
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.micronaut.servlet.jetty

import io.micronaut.context.ApplicationContext
import io.micronaut.context.annotation.Requires
import io.micronaut.core.annotation.Introspected
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Delete
import io.micronaut.http.annotation.Get
Expand Down Expand Up @@ -146,6 +147,7 @@ class JettyCompletableFutureCrudSpec extends Specification {
}


@Introspected
static class Book {
Long id
String title
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ class JettyCorsSpec extends Specification implements TestPropertyProvider {
then:
response.status == HttpStatus.NO_CONTENT
response.contentLength == -1
headerNames.size() == 3
headerNames.contains(CONNECTION)
headerNames.size() == 2
// Client is now keep-alive so we don't get the connection header
!headerNames.contains(CONNECTION)
headerNames.contains(DATE)
headerNames.contains(SERVER)
}

void "test cors request without configuration"() {
Expand All @@ -54,8 +57,11 @@ class JettyCorsSpec extends Specification implements TestPropertyProvider {

then:
response.status == HttpStatus.NO_CONTENT
headerNames.size() == 3
headerNames.contains(CONNECTION)
headerNames.size() == 2
// Client is now keep-alive so we don't get the connection header
!headerNames.contains(CONNECTION)
headerNames.contains(DATE)
headerNames.contains(SERVER)
}

void "test cors request with a controller that returns map"() {
Expand Down Expand Up @@ -140,7 +146,10 @@ class JettyCorsSpec extends Specification implements TestPropertyProvider {

then:
response.code() == HttpStatus.FORBIDDEN.code
headerNames == [CONNECTION, DATE, SERVER] as Set
// Client is now keep-alive so we don't get the connection header
!headerNames.contains(CONNECTION)
headerNames.contains(DATE)
headerNames.contains(SERVER)
}

void "test cors request with invalid header"() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ class JettyHealthSpec extends Specification {

void 'test healthy'() {
given:
def liveness = client.toBlocking().exchange("/health/liveness", HealthResult)
def readiness = client.toBlocking().exchange("/health/readiness", HealthResult)
def overall = client.toBlocking().exchange("/health", HealthResult)
def liveness = client.toBlocking().exchange("/health/liveness", Map)
def readiness = client.toBlocking().exchange("/health/readiness", Map)
def overall = client.toBlocking().exchange("/health", Map)

expect:
liveness.status() == HttpStatus.OK
readiness.status() == HttpStatus.OK
overall.status() == HttpStatus.OK
liveness.status == HttpStatus.OK
readiness.status == HttpStatus.OK
overall.status == HttpStatus.OK
and:"there are no liveness indicators so unknown"
liveness.body().status == HealthStatus.UNKNOWN
liveness.body.get().status == HealthStatus.UNKNOWN as String
and:"readiness indicates up"
readiness.body().status == HealthStatus.UP
readiness.body.get().status == HealthStatus.UP as String
and:'so does overall status'
overall.body().status == HealthStatus.UP
overall.body.get().status == HealthStatus.UP as String
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ class JettyHttpPostSpec extends Specification {
Integer pages
}

@Introspected
static class Params {
List<String> param
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

package io.micronaut.servlet.jetty

import com.fasterxml.jackson.core.JsonParseException
import groovy.json.JsonSlurper
import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Requires
import io.micronaut.core.annotation.Introspected
import io.micronaut.http.HttpHeaders
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
Expand All @@ -16,6 +16,7 @@ import io.micronaut.http.annotation.Post
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.http.codec.CodecException
import io.micronaut.http.hateoas.JsonError
import io.micronaut.http.hateoas.Link
import io.micronaut.test.extensions.spock.annotation.MicronautTest
Expand Down Expand Up @@ -93,8 +94,8 @@ class JettyJsonBodyBindingSpec extends Specification {
then:
response.code() == HttpStatus.BAD_REQUEST.code
response.headers.get(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.APPLICATION_JSON
result['_links'].self.href == '/json/map'
// result.message.startsWith('Invalid JSON')
result['_links'].self.href == ['/json/map']
result['_embedded'].errors[0].message.contains "Unrecognized token 'The'"
}

void "test simple map body parsing"() {
Expand Down Expand Up @@ -397,17 +398,9 @@ class JettyJsonBodyBindingSpec extends Specification {
String requestGeneric(HttpRequest<Foo> request) {
return request.getBody().map({ foo -> foo.toString()}).orElse("not found")
}

@Error(JsonParseException)
HttpResponse jsonError(HttpRequest request, JsonParseException jsonParseException) {
def response = HttpResponse.status(HttpStatus.BAD_REQUEST, "No!! Invalid JSON")
def error = new JsonError("Invalid JSON: ${jsonParseException.message}")
error.link(Link.SELF, Link.of(request.getUri()))
response.body(error)
return response
}
}

@Introspected
static class Foo {
String name
Integer age
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

package io.micronaut.servlet.jetty

import groovy.json.JsonSlurper
import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Requires
import io.micronaut.core.annotation.Introspected
import io.micronaut.http.HttpHeaders
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Error
import io.micronaut.http.annotation.Post
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.http.codec.CodecException
import io.micronaut.http.hateoas.JsonError
import io.micronaut.http.hateoas.Link
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

@MicronautTest
@Property(name = 'spec.name', value = 'JettyJsonBodyBindingSpec2')
class JettyJsonBodyBindingSpec2 extends Specification {

@Inject
@Client("/")
HttpClient rxClient

void "test map-based body parsing with invalid JSON"() {

when:
rxClient.toBlocking().exchange(HttpRequest.POST('/json/map', '{"title":The Stand}'), String)

then:
def e = thrown(HttpClientResponseException)
e.response.getBody(Map).get().message.contains """Unable to decode request body: Error decoding JSON stream for type [json]: Unrecognized token 'The'"""
e.response.status == HttpStatus.BAD_REQUEST

when:
def response = e.response
def body = e.response.getBody(String).orElse(null)
def result = new JsonSlurper().parseText(body)

then:
response.code() == HttpStatus.BAD_REQUEST.code
response.headers.get(HttpHeaders.CONTENT_TYPE) == io.micronaut.http.MediaType.APPLICATION_JSON
result['_links'].self.href == ['/json/map']
result.message.startsWith "Invalid JSON"
result.message.contains "Unrecognized token 'The'"
}

@Requires(property = 'spec.name', value = 'JettyJsonBodyBindingSpec2')
@Controller(value = "/json", produces = io.micronaut.http.MediaType.APPLICATION_JSON)
static class JsonController {

@Post("/map")
String map(@Body Map<String, Object> json) {
"Body: ${json}"
}

@Error(CodecException)
HttpResponse jsonError(HttpRequest request, CodecException jsonParseException) {
def response = HttpResponse.status(HttpStatus.BAD_REQUEST, "No!! Invalid JSON")
def error = new JsonError("Invalid JSON: ${jsonParseException.message}")
error.link(Link.SELF, Link.of(request.getUri()))
response.body(error)
return response
}
}

@Introspected
static class Foo {
String name
Integer age

@Override
String toString() {
"Foo($name, $age)"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@

package io.micronaut.servlet.jetty


import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Requires
import io.micronaut.core.annotation.Introspected
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Error
import io.micronaut.http.annotation.Post
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.http.codec.CodecException
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

import static io.micronaut.http.MediaType.APPLICATION_JSON

@MicronautTest
@Property(name = 'spec.name', value = 'JettyJsonBodyBindingSpec3')
class JettyJsonBodyBindingSpec3 extends Specification {

@Inject
@Client("/")
HttpClient rxClient

void "test map-based body parsing with invalid JSON"() {
when:
rxClient.toBlocking().exchange(HttpRequest.POST('/json/map', '{"title":The Stand}'), String)

then:
def e = thrown(HttpClientResponseException)
e.response.status == HttpStatus.BAD_REQUEST
e.response.getBody().isEmpty()
}

@Requires(property = 'spec.name', value = 'JettyJsonBodyBindingSpec3')
@Controller(value = "/json", produces = APPLICATION_JSON)
static class JsonController {

@Post("/map")
String map(@Body Map<String, Object> json) {
"Body: ${json}"
}

@Error(CodecException)
HttpResponse jsonError(HttpRequest request, CodecException jsonParseException) {
return HttpResponse.status(HttpStatus.BAD_REQUEST, "No!! Invalid JSON")
}
}

@Introspected
static class Foo {
String name
Integer age

@Override
String toString() {
"Foo($name, $age)"
}
}
}
Loading

0 comments on commit f24f3a8

Please sign in to comment.