Change the JsonConverter date format for Play 2.5 - json

I've tried to configure the ObjectMapper for the built-in play.libs.Json. I've followed the documentation, however the MapperLoader seems to be ignored.
This is what I do (based on the documentation):
Create CustomMapperLoader
public class JsonMapperLoader extends GuiceApplicationLoader {
#Override
public GuiceApplicationBuilder builder(final Context context) {
ObjectMapper mapper = Json.newDefaultMapper()
.setDateFormat(new SimpleDateFormat(Constants.ISO8601_DATE_FORMAT));
Json.setObjectMapper(mapper);
return super.builder(context);
}
}
Explicitly load the loader in application.conf:
play.application.loader = "JsonMapperLoader"
When I serialize date, it still gives me the time-stamp instead of specified format.
I have several workarounds for this:
I set the object mapper during the creation of
ApplicationController
I disable the play.core.ObjectMapperProvider and enable my CustomObjectMapperProvider.
Is there any better alternatives for this issue?
Thanks & Regards,

I never tried the method suggested in the manual (with custom ApplicationLoader). I use another technique. In short: there is a class, which configures the ObjectMapper; the class is injected it in the Module as a singleton.
You can see the full code example here.

Related

Use two differently configured ObjectMappers in one Spring Boot application

I am working on a middleware-app which deserializes values received via RestTemplate as json-String from a legacy-API (so, no influence on "their" data model and thus needing some custom config for my objectmapper consuming this api), and the app itself serves a restful API with (partially enriched and composited) data based on the legacydata as json, too.
Now, my legacy-Mapping-Classes' Constructors are all sharing a common structure like this at the moment:
...
private ObjectMapper mapper;
public MyMapper() {
this.mapper = new ObjectMapper();
this.mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
...
because I use Jackson to de-serialize the json from the legacysystem. Basically I want to refactor this redundance using Springs DI Container.
So I tried to create my own Objectmapper #Component which just extends ObjectMapper like it is stated in some answers in this thread:
Configuring ObjectMapper in Spring - lets call it FromLegacyObjectMapper - instead of initializing my mapper in every class, so I created one and used
#Autowired
private FromLegacyObjectMapper
(or the constructorinjection-equivalent, but for simplicitys sake..).
But this had some serious sideeffects. Actually, I wasn't able to deserialize clientjson to viewmodels in my controllers anymore because of the rootvalue-wrapping, because the autowiring overwrites the spring boot standard objectmapper which I actually need when deserializing viewModels from my frontend.
I try to get it up and running like this:
frontend <---> My Api using Standard ObjectMapper <--> viewModel created by consuming legacy-Api-json using FromLegacyObjectMapper
So, what I surely could do is using a baseclass for my mappingclasses and just add the code above to the base constructor, and let every Mapperclass extend this base, but actually I hoped to find a way to use springs dependency injection container instead. I am out of ideas for now, so I hope anyone could help me out!
edit: To make it perhaps a bit clearer please see Moritz' answer below and our discussion in the comments. I am well aware I am able to use #Qualifier annotation, but this would just solve the problem if there is a way to add the #Qualifier to the standard objectmapper used in spring controllers. I'll do some research myself, but other answers are highly welcome.
I would try adding two different ObjectMappers to the Spring container. You could add something like this, for example to your Application class (assuming that is the one annotated with #SpringBootApplication):
#Bean
#Qualifier("fromLegacy")
public ObjectMapper fromLegacyObjectMapper() {
// create and customize your "from legacy" ObjectMapper here
return objectMapper;
}
#Bean
#Qualifier("default")
public ObjectMapper defaultObjectMapper() {
// create your default ObjectMapper here
return objectMapper;
}
Then you can inject the "from legacy" ObjectMapper in classes that use the legacy API like this:
public class SomeServiceUsingLegacyApi {
private final ObjectMapper objectMapper;
#Autowired
public SomeServiceUsingLegacyApi(#Qualifier("fromLegacy") ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
// [...]
}
And in other classes, using the other API accordingly:
public class SomeServiceUsingOtherApi {
private final ObjectMapper objectMapper;
#Autowired
public SomeServiceUsingOtherApi(#Qualifier("default") ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
// [...]
}

Spring 4 and RabbitMQ json type

I'm really stuck with cast Rabbit response to POJO. How to do it properly? On sprin.io just no practical example.
So I'm trying to do it with this
#Bean
public DefaultClassMapper typeMapper() {
DefaultClassMapper typeMapper = new DefaultClassMapper();
Map<String, Class> idClassMapping = new HashMap<String, Class>();
idClassMapping.put("range", Loan.class);
typeMapper.setIdClassMapping(idClassMapping);
//typeMapper.setDefaultType(Loan.class);
return typeMapper;
}
#Bean
public MessageConverter messageConverter(DefaultClassMapper defaultClassMapper){
JsonMessageConverter jsonMessageConverter = new JsonMessageConverter();
jsonMessageConverter.setClassMapper(defaultClassMapper);
return jsonMessageConverter;
}
"range" actually fake value from example. Also this really doesn't work type problemn on .setIdClassMapping() . Also I can't use default mapper because serve send header without type hinting field. And I have no control on this remote server. Data format always JSON.
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to convert Message content. Could not resolve __TypeId__ in header
Any suggestions working example for marshalling/demarshalling Java objects. I have completely different class for send back value from my code. I'm using java 8.
Just write your own ClassMapper - don't use the default one if your decision criteria to choose the class type is not compatible with its internals.
Or, you can subclass the DefaultClassMapper and override getClassIdFieldName() to tell it which message property to use.

Custom Neo4j GraphViz Writer

I have an application which produces a GraphViz dot file for a subgraph of my Neo4j database. It works like a charm, but there is somewhat of an issue.
Right now, the title of each node is the node id. Then the properties are listed, with their respective types. This is more information than I need and I would like to change the way the GraphViz writer is configured.
I noticed several classes/interfaces such as GraphStyle, StyleParameter, StyleConfiguration but I've tried several things and keep running into the issue that I cannot access certain classes/interfaces outside of their respective package. Maybe I'm doing it wrong, maybe it's designed so users cannot reconfigure the GraphViz writer, I don't know but I'd like to know.
How do I reconfigure the GraphViz writer so the dot file contains only that information which I want it to contain, namely a property of my choosing as the title, and nothing else as far as the nodes are concerned. Also, this is not always the same property, so for some nodes I'd like property A to be the title, and for nodes that don't have property A, I'd like property B to be the title.
Any help would be greatly appreciated.
You could try using the styles provided by this class: https://github.com/neo4j/neo4j/blob/master/community/graphviz/src/main/java/org/neo4j/visualization/graphviz/AsciiDocSimpleStyle.java
It might be useful to look into this class as well: https://github.com/neo4j/neo4j/blob/master/community/graphviz/src/main/java/org/neo4j/visualization/asciidoc/AsciidocHelper.java
I managed to get it to work. First of all, you need to create two new classes:
class NodeStyleImpl implements NodeStyle
class RelationshipStyleImpl implements RelationshipStyle
Here you can define how nodes and relations should be written in the dot notation. An example implementation looks like this :
public class NodeStyleImpl implements NodeStyle {
public void emitNodeStart(Appendable apndbl, Node node) throws IOException {
apndbl.append(" N" + node.getId() + " [\n label = \"");
}
public void emitEnd(Appendable apndbl) throws IOException {
apndbl.append("\"\n]\n");
}
public void emitProperty(Appendable apndbl, String propkey, Object propvalue) throws IOException {
if(propkey.equals("propkeyone") || propkey.equals("propkeytwo"){
apndbl.append(propvalue.toString());
}
}
}
In an analog fashion, you can write the RelationshipStyleImpl. If you're looking for more advanced configuration, you can also write a StyleConfiguration implementation. You can look at the default implementations in the Neo4j code for an example.
Then there's the issue with the GraphStyle class. The GraphStyle class has a constructor which is protected, thus only accessible from within the package. I made a pull request to change it to public but for the moment, here's a little "hack" which provides a workaround.
package org.neo4j.visualization.graphviz
public class GraphStyleImpl extends GraphStyle {
private GraphStyleImpl (NodeStyleImpl nstyle, RelationshipStyleImpl rstyle) {
super(nstyle, rstyle);
}
}
Note the package declaration. Because the GraphStyle constructor is protected, the super(nstyle, rstyle) method is only accessible from within the same package. By extending the class with a new public constructor, you can now do the following:
GraphStyle graphstyle = new GraphStyleImpl(new NodeStyleImpl(), new RelationshipStyleImpl());
GraphvizWriter writer = new GraphvizWriter(graphstyle);
If my pull request gets accepted, the use of the GraphStyleImpl class will no longer be necessary.

Jackson 1.9.0: JsonTypeInfo for abstract class not working with Lists

Using this abstract class:
#JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
#JsonSubTypes({ #JsonSubTypes.Type(value = PostingTaskInstanceDto.class, name = "TI") })
public abstract class BasePostingDto {}
and this inherited class:
public class PostingTaskInstanceDto extends BasePostingDto {}
I get correct serialization for a single object. This works, using Spring-MVC:
#RequestMapping("/{id}")
#ResponseBody
public BasePostingDto findById(#PathVariable("id") Long id) {
return createDto(postingService.findById(id));
}
But if I retrieve a List of BasePostingDto from the remote controller, the type property is missing:
#RequestMapping("/by-user/all")
#ResponseBody
public List<BasePostingDto> findByUser() {
return createDtoList(postingService.findByUser(AuthUtils.getUser()));
}
Why is this and how can I force the type property?
Update: the type property is also included if I change List<BasePostingDto> to BasePostingDto[], however I would prefer to go with the List.
It sounds like the framework you are using (and which uses Jackson under the hood) is not passing full generics-aware type information.
I don't know how that can be fixed (it is problem with integration by framework, and not something Jackson can address), but the usual work around is for you to use sub-class of List:
public class PostingDtoList extends List<BasePostingDto> { }
and use that in signature, instead of generic type. This solves the issue because then the generic type signature is retained (since it is stored in super type declaration, and accessible via type-erased PostingDtoList class!).
In generally I think it is best to avoid using generic List and Map types as root type (and instead use POJO); partly because of problems issued (there are bigger problems when using XML for example). But it can be made to work if need be.

How to customize Jackson type information mechanism

In Jackson, I am using annotation #JsonTypeInfo to include polymorphism support.
If, I do not want to go with annotation based approach, I can use global default typing or override the type information handling module.
I have tried global type information but it is emitting type information for all non final type.
What I need ,
I want to include type information only for polymorphic type.
I want to change default format of type info (to key-value pair)
Is it possible to achieve above two points just by twitting global configuration?
If not, what extension point should I used used to customize type-information module ?
I have read JacksonAnnotationIntrospector is the class which deals with type info.
Should I customize it to achieve above mentioned two points?
Help with Example will be well and good.
You can use Jackson's DefaultTypeResolverBuilder for this purpose. Extend this class and override the useForType method appropriately. Here is an example that adds type information only for the classes belonging to the test.jackson package (and sub-packages):
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTypeResolverBuilder;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
public class CustomTypeResolverBuilder extends DefaultTypeResolverBuilder
{
public CustomTypeResolverBuilder()
{
super(DefaultTyping.NON_FINAL);
}
#Override
public boolean useForType(JavaType t)
{
if (t.getRawClass().getName().startsWith("test.jackson")) {
return true;
}
return false;
}
}
Now, consider that you have Foo.java in test.jackson package and Bar.java in org.myorg package, each containing an int variable called "integer" and a String variable called "string".
You can serialize objects of these two classes this way:
ObjectMapper objectMapper = new ObjectMapper();
TypeResolverBuilder<?> typeResolver = new CustomTypeResolverBuilder();
typeResolver.init(JsonTypeInfo.Id.CLASS, null);
typeResolver.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolver.typeProperty("#CLASS");
objectMapper.setDefaultTyping(typeResolver);
Foo foo = new Foo(10, "Foo");
Bar bar = new Bar(20, "Bar");
System.out.println(objectMapper.writeValueAsString(foo));
System.out.println(objectMapper.writeValueAsString(bar));
The corresponding output will be:
{"#CLASS":"test.jackson.Foo","integer":10,"string":"Foo"}
{"integer":20,"string":"Bar"}
You can also customize the name of the attribute that represents the type ("#CLASS" in the above example). Hope this helps!
You can use the Moonwlker library.
With it, you can create an ObjectMapper like this:
ObjectMapper objectMapper = new ObjectMapper();
MoonwlkerModule module =
MoonwlkerModule.builder()
.fromProperty("#CLASS").toSubclassesOf(Animal.class)
.build();
objectMapper.registerModule(module);
And then use that mapper to (de)serialize. The Moonwlker website contains more details and configuration options.