Spring Boot and Jackson, JSR310 in response body - spring-boot

The JacksonAutoConfiguration initializes an ObjectMapper with the JSR310Module registered. Then HttpMessageConvertersAutoConfiguration initializes a MappingJackson2HttpMessageConverter. But this MessageConverter never gets plugged in the RequestResponseBodyMethodProcessor.
As a result:
If the controller returns a object which should be jsonified by Jackson, dates are poorly converted because the wrong MappingJackson2HttpMessageConverter is used (initialized in WebMvcConfigurationSupport#addDefaultHttpMessageConverters)
But, if the ObjectMapper is injected in the controller and used to jsonify the same object, then the date format is alright.
How can I can wake the WebMvcAutoConfigurationAdapter up? What should I do to bind the configured Jackson ObjectMapper with Spring MVC and make it handle response bodies?

If you use #EnableWebMvc that would explain your symptoms So the rule thumb is: do not use #EnableWebMvc with Spring Boot, unless you wan't to customize Web MVC configuration?

Related

MappingJackson2HttpMessageConverter isn't using the ObjectMapper configured by a #Bean

i am using spring-boot 3.0.2 and have created a custom jackson serializer and registered it using #JsonComponent. i have confirmed it is registered in the ObjectMapper instance that gets injected using #Autowire. when i go to invoke the rest endpoint that will return an object that should be handled by the custom serializer, it is never by the RequestResponseBodyMethodProcessor.
after doing some digging it seems only the default set of converters created in WebMvcConfigurationSupport are being used and nothing else. i have tried registering my own instance of MappingJackson2HttpMessageConverter as a #Bean but it is never used.
the only way i have found to fix this issue is to replace whatever default is being created using extendMessageConverters in WebMvcConfigurer.
can anyone offer any suggestions? from the various blog posts i've read, this should just work but appears not to.
i expect json that looks like this:
["fqdn":"test.com"]
but instead get:
["fqdn:{"idnEncoded":false,"domainName":"test","tldName":"com"}]

JerseyConfig and #Profile to hide a REST endpoint

I'm trying to hide a REST endpoint based on runtime configuration in Spring and Jersey. The most straightforward way is to throw the NotFoundException from the controller itself but maybe there's more kosher. The controller is registered in the constructor of the config class which extends org.glassfish.jersey.server.ResourceConfig.
I thought of using the #Profile annotation on the controller but I can still access the endpoint. When I hit that endpoint, I get the following error:
o.g.j.s.s.SpringComponentProvider - None or multiple beans found in Spring context
but then Jersey manages to access that controller, which I confirmed by attaching a debugger to the Spring process. So Jersey does not honor the #Profile setting.
On a separate note, I also have Swagger plugged into Jersey and when accessing the definition endpoint (.../swagger.json) I can see the endpoint provided by the #Profile-disabled controller.
Is there anything better I can do here is is throwing the NotFoundException the best option?
Note: Sorry, I thought I saw that you were using Spring Boot. The following answer is only relevant for Spring Boot.
#Profile is only good for Spring bean registration, but you are still registering the service with Jersey as a resource. What you can do is use a ResourceConfigCustomizer and add the #Profile to the customizer. This way it will only register the resource with Jersey ResourceConfig if the correct profile is active.
#Component
#Profile("..")
public class MyResourceConfigCustomizer implements ResourceConfigCustomizer {
#Override
public void customize(ResourceConfig config) {
config.register(MyResource.class);
}
}

How can I force #AutoConfigureJsonTesters to use HAL format from spring-hateoas?

I have a small module that should only contain the resource model of my REST service. I want to create a test in this module to ensure that the resource model serializes and deserializes appropriate HAL format.
I have a single test and this is the configuration:
#RunWith(SpringRunner::class
#SpringBootTest
#AutoConfigureJsonTesters
class MyTest {
#Autowired
private lateinit var collectionTester: JacksonTester<Resources<Entity>>
....
}
and a very simple configuration
#SpringBootConfiguration
class TestConfig
When calling collectionTester.write on a list of Entity (which extends ResourceSupport) I don't get an _embedded field, instead I get
{"links":[],"content":[...]}
which is not HAL format.
How can I force #AutoConfigureJsonTesters to give me a JacksonTester with an ObjectMapper configured for HAL?
Spring Boot 2.0.0.RELEASE
Thanks!
The auto-configured JacksonTester will use the context’s ObjectMapper which won’t have any of the Spring HATEOAS stuff configured on it. You might be better creating a JacksonTester yourself and passing it an appropriately configured ObjectMapper to use.
I believe Spring HATEOAS has a module that it applies to the ObjectMapper to configure it. If you get stuck with that, asking in gitter/spring-projects/spring-data is probably your best bet as Spring HATEOAS is maintained by the Data team due to it being used by Spring Data REST.

Why do we need #Component spring annotation for Jersey resource in spring-boot-starter-jersey project?

This question is regarding the sample:
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/Endpoint.java
Why do we need "#Component" annotation for Jersey resource when using spring-boot -starter-jersey project?
If I remove it, the Jersey servlet can still serve resources.
So what is the need for "#Component"?
You don't need it. Jersey uses HK2 as it's internal DI framework, and HK2 has a Spring bridge. This is what's used internally to bridge Spring components into the HK2 IoC container, so that they can be injected into Jersey components. And Jersey implements an AutowiredInjectionResolver1 that allows for injection of Spring components using #Autowired. You don't even need #Autowired though. All the Spring components can be injected with the normal #Inject.
The only drawback I've ran into, not making the Jersey components a Spring #Component is that it doesn't support #Value when you want to inject property values.
The one thing I don't like is that when you declare something a Spring #Component, it automatically makes it a singleton. But Jersey resources are by default request scoped. You can add a Spring #Scope("request"), and it should change the resource to a request scoped resource. Jersey has declared the Spring RequestScope, so we can use it. How exactly it ties in to Jersey's request scope, I am not a hundred percent sure. I ran into a problem a while back. I can't remember what it was, but that has kept me from ever using the Spring request scope again.
Assuming I want to keep all my resources request scoped, I would take sticking to the normal Jersey request scope, and not being able to inject #Values, over having to use Spring's request scope. Maybe I'm imagining things, and there was no issue using it, but personally I'll just stick to what I know works :-)
UPDATE
Another thing that does't work if you don't make the resource a Spring #Component is Spring's AOP. That's fine with me though as HK2 also has AOP.
1 - An InjectionResolver allows you to use custom annotations to create injection targets.
When you remove #Component jersey takes control of the scope of the instance. With #Component a singleton instance is created, removing it you can use the following jersey annotations:
• Request scope (Default):
By using the #RequestScope annotation or none, we can have a life-cycle till
the request lasts. This is the default scope of the root-resource classes. For
each new request, a new root-resource instance is being created and served
accordingly for the first time. However, when the same root-resource method
is being called, then the old instance will be used to serve the request.
• Per-lookup scope:
The #PerLookup annotation creates root-resource instances for every request.
• Singleton:
The #Singleton annotation allows us to create only a single instance
throughout the application.
Try different behaviors using a counter inside your class...
public class MyWebResource {
private int counter;
#GET
#Path("/counter")
#Produces(MediaType.APPLICATION_JSON)
public Response getCounter() {
counter++;
return Response.status(Status.OK).entity(counter).build();
}
}

Spring-Boot 0.5.0.BUILD-SNAPSHOT and customer Json MappingJackson2HttpMessageConverter

Has anyone working with Spring-Boot figured out how to override the default Jackson ObjectMapper that is automatically configured? I have tried to instantiate both the ObjectMapper as a bean and within a MappingJackson2HttpMessageConverter also as a been. But with no success...
Any thoughts?
Spring handles HTTP #ResponseBody using the HttpMessageConverter abstraction, so it's there that you would have to add customizations. Normally you would add a #Bean extending WebMvcConfigurerAdapter and override the configureMessageConverters() method.
Adding a #Bean of type ObjectMapper sounds like a neat way to do this for a Spring Boot application, so you could provide that feature in a pull request if you like.

Resources