Corda RPC JacksonSupport.createDefaultMapper to use ObjectMapper in Spring client - spring

How to register newly introduced Corda RPC ObjectMapper in Spring Boot?
Even after having below code in #Configuration class Jackson failing to serialize Party object to JSON string.
#Bean
public JsonComponentModule jsonComponentModule() {
return new JsonComponentModule();
}
#Bean
#Primary
public ObjectMapper cordaRpcObjectMapper(NodeRPCConnection rpc) {
ObjectMapper objectMapper = JacksonSupport.createDefaultMapper(rpc.getProxy(), new JsonFactory(), true);
objectMapper.registerModule(jsonComponentModule());
return objectMapper;
}

After some tweaks I'm successfully able to register Corda RPC ObjectMapper with Jackson with below code.
//Register any other custom (de)Serializer classes.
#Bean
public Module jsonComponentModule() {
return new JsonComponentModule();
}
//Force Spring/Jackson to use only provided Corda ObjectMapper for serialization.
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(#Autowired NodeRPCConnection rpcConnection) {
ObjectMapper mapper = JacksonSupport.createDefaultMapper(rpcConnection.getProxy()/*, new JsonFactory(), true*/);
mapper.registerModule(jsonComponentModule());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(mapper);
return converter;
}

Related

MappingJacksonHttpMessageConverter cannot be resolved to a type

I am trying to upgrade Spring Application (not using Spring Boot) from 2.3.2.RELEASE to 5.3.20 (latest version as of today), I do see below code is breaking and
Code:
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
ObjectMapper defaultMapper = new ObjectMapper();
defaultMapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, true);
defaultMapper.configure(SerializationConfig.Feature.REQUIRE_SETTERS_FOR_GETTERS, true);
mappingJacksonHttpMessageConverter.setObjectMapper(defaultMapper);
converters.add(mappingJacksonHttpMessageConverter);
}
What's the replacement of import org.codehaus.jackson.map.ObjectMapper to jacksondata bind for below code?
ObjectMapper defaultMapper = new ObjectMapper();
defaultMapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, true);
defaultMapper.configure(SerializationConfig.Feature.REQUIRE_SETTERS_FOR_GETTERS, true);
mappingJacksonHttpMessageConverter.setObjectMapper(defaultMapper);
I was able to do like below
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);
objectMapper.configure(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, true);
mappingJacksonHttpMessageConverter.setObjectMapper(objectMapper);
The MappingJacksonHttpMessageConverter is for Jackson1, which isn't supported anymore with Spring 5, it was deprecated in Spring 4.
You will need to migrate to Jackson2 and use the MappingJackson2HttpMessageConverter instead.
Instead of constructing the ObjectMapper manually I strongly suggest using the Jackson2ObjectMapperBuilder to construct the ObjectMapper. It will automatically detect and register well known Modules and allows for easier configuration.
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
ObjectMapper mapper = Jackson2ObjectMapperBuilder.json()
.defaultViewInclusion(true)
.featuresToEnable(SerializationConfig.Feature.REQUIRE_SETTERS_FOR_GETTERS)
.build();
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter(mapper);
converters.add(converter);
}
Finally use the constructor instead of the setter as that saves building an additional ObjectMapper (done in the default constructor of the MappingJackson2HttpMessageConverter and then throwing it away) saves a few CPU cycles.

Customise JSON date formatting of JSON for spring-mvc (non-boot)?

I am converting my app to get rid of spring-boot, it now uses only Spring (5.3).
I've added the #EnableWebMvc configuration and I have my endpoints working properly for the most part - they return the data I want as JSON.
Previously, I customised the date format with the spring-boot property: spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
In the new pure-spring app though, it's regressed back serializing to a long value.
I've tried the following, but it doesn't seem to even use these beans at all:
#Bean
public ObjectMapper objectMapper() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
ObjectMapper dateFormatMapper = new ObjectMapper();
dateFormatMapper.setDateFormat(dateFormat);
return dateFormatMapper;
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2JsonView(){
var converter = new MappingJackson2HttpMessageConverter();
converter.getObjectMapper().setDateFormat(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") );
return converter;
}
I'm looking to customise the format globally, not on a per-field basis.
What would be the equivalent of spring.jackson.date-format for pure Spring #EnableWebMvc setup?
You can customize MappingJackson2HttpMessageConverter by using WebMvcConfigurer with #EnableWebMvc.
For example:
#Configuration
#EnableWebMvc
public class YourConfiguration implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
}
For more information, please see 1.11.7. Message Converters - Web on Servlet Stack - docs.spring.io.

Spring Jackson custom Deserializer does not called

I have a Spring project, and I try to add a custom deserializer to deserialize Date properties depend on their format.
If I use it as annotation on Date property, it works fine.
But if I add the deserializer to my object mapper, it does not called when Jackson deserialize a date.
I try to apply my custom deserializer like this:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Date.class, new DateDeserializer());
mapper.registerModule(module);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
return mapper;
}
I don't want to apply an annotation on Date properties every time, I want to use this deserializer by default.
What I do wrong?
Thanks the help for everyone.
Finally I found the answer at spring.io.
#Configuration
#EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.deserializerByType(Date.class, new DateDeserializer());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
}
Given that if you use the deserializer in an annotation on Date property then I would say that this ObjectMapper is not being used for deserialization. Try the following:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
jsonConverter.setObjectMapper(objectMapper);
return jsonConverter;
}
I have doubt how you try to use this ObjectMapper bean inside your application.
I trust you already know that this bean is need to created inside a Configuration class. If not your bean will not register in the context. Like this for example,
#Configuration
public class MapperConfig {
#Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Date.class, new DateDeserializer());
mapper.registerModule(module);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
return mapper;
}
}
The second problem might be how you try use this ObjectMapper bean. If your create new instance of ObjectMapper like this ObjectMapper objectMapper = new ObjectMapper();, that instance will not have your custom deserializer and stuff. What you can do is #Autowire the ObjectMapper instance that you have already created.

How to configure HttpMessageConverter for specified controller in SpringMvc

As we know, we can configure the global HttpMessageConverter by configureMessageConverters method in WebMvcConfigurer.
see https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-config-message-converters
But I want to configure a HttpMessageConverter for specified Controller to override the global configuration to implement the function different from the global.
How should I configure it? Can any friends give me pointers?
You can put below code in any of your configuration classes. and you have to autowire this specific objectmapper in that class where you need.Even you can create multiple objectmappers to serve different purposes.
#Bean
#Qualifier("customForController")
public ObjectMapper getObjectMapper() {
ObjectMapper mapper=new ObjectMapper();
return mapper;
}
#Bean
#Qualifier("customMessageConverter")
public MappingJackson2HttpMessageConverter converter() {
MappingJackson2HttpMessageConverter httConverter = new MappingJackson2HttpMessageConverter();
httConverter.setObjectMapper(getObjectMapper());
//others configuration goes here
return httConverter;
}

Spring Cloud Security Resource Server and JSON Vulnerability Protection

According to JSON Vulnerability Protection I prefix JSON responses:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setJsonPrefix(")]}',\n");
return converter;
}
It works fine with AngularJS, but not with #EnableOAuth2Resource-App, because Jackson can't parse response from Authorization Server. Firthermore, I can't override
#Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
definition from org.springframework.cloud.security.oauth2.resource.ResourceServerTokenServicesConfiguration.JwtTokenServicesConfiguration to configure ObjectMapper/RestTemplate because of autoconfiguration ordering and SPR-13980.
Maybe I'm missing a solution?

Resources