I've read many articles/threads and what not about how to enable Jackson's WRAP_ROOT_VALUE feature in SpringBoot (v2.2.2RELEASE) and none of them really work, until I came across the following solution which does the trick!
#Configuration
public class JacksonConfig
#Bean
#Primary
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() //
.featuresToEnable(SerializationFeature.WRAP_ROOT_VALUE); // enables wrapping
return builder;
}
This works since it replaces SpringBoot/Swagger's serialization definitions with this custom one.
The problem: Swagger3 stop working! I access swagger using this link:
http://localhost:8080/swagger-ui/index.html and it stopped working! If I remove the JacksonConfig then everything is back to normal.
My assumption is that Swagger initializes Jackson in some way that ruins my custom one.
Any idea?
Related
I’m using Spring AMQP and Spring Boot #Configuration and #Bean annotations in order to create all required queues, exchanges and bindings.
#Bean
public Queue queue() {
return new Queue("my_old_queue", true, false, false);
}
#Bean
public Exchange exchange() {
return new DirectExchange("MY_OLD_EXCHANGE");
}
#Bean
public Binding binding() {
return BindingBuilder.bind(queue())
.to(exchange())
.with("old_binding")
.noargs();
}
But I’ve faced with a problem of upgrading my topology:
I wanna add a new queue/binding/exchange
And remove an old queue/binding/exchange (even if it was durable entity).
Does some annotation exists for removing or unbinding (like #Unbind)?
I’ve seen the example where RabbitManagementTemplate was suggested, but it’s a completely different way of configuration - I wanna keep everything in the single #Configuration class and use annotations or config beans only (is it possible?).
Does some common pattern exists for creating/removing and updating rabbit topology (maybe I missed something)?
You cannot delete entities with annotations or configuration, use the RabbitAdmin.delete*() methods to remove them like in that answer - the management template was used to list the bindings, the RabbitAdmin (amqpAdmin) does the removals.
I'm trying to implement RFC 7807 in my Spring Boot project using zalando problem-spring-web https://github.com/zalando/problem-spring-web
I've done the setup according to this guide https://github.com/zalando/problem-spring-web/tree/master/problem-spring-web
When an exception is thrown, the Problem instance does get generated, but its serialized JSON form is not as expected, most notably the stack trace is included when it shouldn't.
After some debugging, it seems that the ProblemModule is not registered in the ObjectMapper that is used to serialize the problem (its setupModule method is never called). I was under the impression that declaring a bean of type Module was enough to have it picked up by Spring and registered in the ObjectMapper, but it doesn't happen here.
The doc says
In case you want to enable stack traces, please configure your
ProblemModule as follows:
ObjectMapper mapper = new ObjectMapper()
.registerModule(new ProblemModule().withStackTraces());
which seems to imply that you need to instantiate your own ObjectMapper, but then how to make sure that it's used by the library when deserializing the Problem?
Since I can't get the ObjectMapper to register my Modules I figured I had to do it myself so I came up with this solution that seems to work:
#Configuration
public class ProblemConfiguration implements InitializingBean {
#Autowired
ObjectMapper objectMapper;
#Override
public void afterPropertiesSet() {
objectMapper.registerModules(
new ProblemModule(),
new ConstraintViolationProblemModule()
);
}
}
If someone has an idea why it's not working as expected, I'd be glad to hear it :)
Since Spring boot 1.1.0, the JacksonAutoConfiguration creates an ObjectMapper bean and automatically registers all module found in your registered beans,
so you juste need to create does two beans modules and use de already configured ObjectMapper like this:
/*
* Module for serialization/deserialization of RFC7807 Problem.
*/
#Bean
public ProblemModule problemModule() {
return new ProblemModule();
}
/*
* Module for serialization/deserialization of ConstraintViolationProblem.
*/
#Bean
public ConstraintViolationProblemModule constraintViolationProblemModule() {
return new ConstraintViolationProblemModule();
}
use configured ObjectMapper for ex in service Classe
#Autowired
ObjectMapper jacksonObjectMapper
I want to use JAXB annotations instead of Jackson's annotations for XML serialization and deserialization.
I'm using Spring Boot 2.1.3 which uses Spring 5.1.5 and Jackson 2.9.8.
So I defined my customizer bean
#Bean
Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return (mapperBuilder) -> mapperBuilder
.modulesToInstall(new JaxbAnnotationModule())
.defaultUseWrapper(false);
}
which works automatically in Spring MVC #RestControllers.
However it does not apply to requests/responses made with a RestTemplate.
For the RestTemplate to work I had to define a special MappingJackson2XmlHttpMessageConverter bean.
#Bean
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter(
Jackson2ObjectMapperBuilder builder) {
XmlMapper mapper = builder.createXmlMapper(true).build();
return new MappingJackson2XmlHttpMessageConverter(mapper);
}
Then, when the RestTemplate is needed I build it myself:
#Autowired
public AClient(RestTemplateBuilder restTemplateBuilder, MappingJackson2XmlHttpMessageConverter xmlHttpMessageConverter) {
this.xmlRestTemplate = restTemplateBuilder
.messageConverters(xmlHttpMessageConverter)
.build();
}
My problems with this approach are:
I have to define and autowire a second bean, how can I avoid the duplication of configuration?
The template I build is only valid for XML. I tried addMessageConverters but it yields weird errors with content negotiation.
In integration tests this means I have to mock the builder to create the same template to bind the mock MVC server to. This can get messy as soon as other template configurations pop up.
What I wish for: A single bean that provides a customizer and applies to Spring's MVC endpoints as well as the RestTemplateBuilder (replacing the default XmlHttpMessageConverter).
I'm using spring-boot and want to customize the ObjectMapper created.
What I want to do is be able to serialize objects that do not have a getter or setters. Before this could be done by putting JsonAutoDetect.Visibility.ANY on the ObjectMapper.
But how can I enable this feature using the Jackson2ObjectMapperBuilder bean I'm currently exposing ?
You can use a Jackson2ObjectMapperBuilder subclass that overrides the configure(ObjectMapper) method:
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
return new Jackson2ObjectMapperBuilder() {
#Override
public void configure(ObjectMapper objectMapper) {
super.configure(objectMapper);
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
}
};
}
If you want to keep the ObjectMapper configurable through the spring.jackson.* properties that Spring Boot provides, then you better don't define your own Jackson2ObjectMapperBuilder bean (check JacksonObjectMapperBuilderConfiguration inside JacksonAutoConfiguration class for details).
What you can do instead is this:
#Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder mapperBuilder) {
return mapperBuilder.build().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
}
I spend a half of day to play with different settings.
So I manage to work it (1.3.2.RELEASE) when:
I configure jackson in simple #Configuration annotated config class (not extended from WebMvcConfigurerAdapter)
I have NOT#EnableWebMvc
Then Jackson2ObjectMapperBuilder objectMapperBuilder solution is
work, but spring.jackson.serialization.indent_output: true in properties ignored.
At last I finished with
#Autowired(required = true)
public void configeJackson(ObjectMapper objectMapper) {
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
}
But all this is puzzle for me. I wrote a question about any explanation of all this magic in order to have some undestanding and solve problem not by
trial-and-error method: Are there any Spring Boot documentation for understanding how web mvc configuration is work?
I'm using Spring 4 and was following the Rossen Stoyanchev's blog post about using websockets in Spring. I was able to get everything working but I'm not sure what the best way to use a custom object mapper when sending application/json.
I'm injecting a SimpMessageSendingOperations and calling convertAndSend. I'm not positive but I'm pretty sure I'm getting a SimpMessagingTemplate (it implements SimpMessageSendingOperations) which contains a setMessageConverter. This method takes a MessageConverter and there is a MappingJackson2MessageConverter class but of course it uses it's own internal ObjectMapper which cannot be redefined.
So what it looks like I have to do is create a custom MessageConverter and define my custom ObjectMapper within it so I can pass it to an instance of SimpMessagingTemplate that I can then inject into my classes.
This seems like it would work, but also more involved than I expected. Am I overlooking something?
Looks like it is possible, but will be made easier in Spring 4.0.1
See - https://jira.springsource.org/browse/SPR-11184
Quote from the bug report above.
In the mean time, with #EnableWebSocketMessageBroker setup you can:
remove the annotation
extend WebSocketMessageBrokerConfigurationSupport instead of implementing WebSocketMessageBrokerConfigurer
override brokerMessageConverter() method and remember to keep #Bean in the overriding method
Nowadays you can do it like this:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
// Avoid creating many ObjectMappers which have the same configuration.
converter.setObjectMapper(getMyCustomObjectMapper());
messageConverters.add(converter);
// Don't add default converters.
return false;
}
...
}
Unfortunately ObjectMapper cannot be given directly to MappingJackson2MessageConverter's constructor, meaning it will first create a useless ObjectMapper.