Imagine a situation when you have a model in Java, and you have to serialize it both to XML and CSV.
I am using Jaxb Marshaller for XML and Jackson's CsvMapper (ObjectMapper) for CSV.
Since the formats are slightly different, I want Jackson's CsvMapper to ignore Jaxb related annotations like #XmlType or #XmlElement. Because Jackson is getting information/considers xml annotations as well and it leads to wrong result.
How can I do it?
This is the way how you probably create new CsvMapper:
CsvMapper csvMapper = new CsvMapper();
csvMapper.findAndRegisterModules();
findAndRegisterModules method invokes findModules which documentation says:
Method for locating available methods, using JDK ServiceLoader facility, along with module-provided SPI.
So, probably you have jackson-module-jaxb-annotations module on class path and this is why CsvMapper recognizes JAXB annotations.
To fix it, you need to remove invocation of this method findAndRegisterModules and register only these modules you needed.
Related
Is there a way to tell Jackson to always serialize one type to another. In my case I would like to always serialize Long to String. Right now whenever there is an object with a Long property we have to annotate it with #JsonSerialize(using=ToStringSerializer.class). This is tedious and easy to forget.
I would like to be able to configure the Jackson object mapper to always convert Long to String in the spring boot bean creation.
IMHO, multiple options are there.
I
com.fasterxml.jackson.databind.ser.std.StdSerializer implementation that can be set to your ObjectMapper in the spring context.
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
....
builder.serializerByType(<type>, <your custom serializer>);
return builder;
}
As for the custom serializer, you can extend the above-mentioned class StdSerializer.
II
spring.jackson.generator.write-numbers-as-strings=true
Note
Be aware of that Feature.WRITE_NUMBERS_AS_STRINGS has deprecated Since 2.10 of jackson version.
I hope it helps.
This can be done using this serialization feature.
jsonGenerator.configure(Feature.WRITE_NUMBERS_AS_STRINGS,true);
http://fasterxml.github.io/jackson-core/javadoc/2.10/com/fasterxml/jackson/core/json/JsonWriteFeature.html#WRITE_NUMBERS_AS_STRINGS
I'm working on aria2 jsonrpc remote revoke, and I found out that all aria2 accept are strings value, like number 1 should be "1".
Although I can use JsonSerializer Annotation or use Module method, I think there should be an easy way which could apply "Int to String Serializer" to all of the fields of type int.
Could anyone give me a hint how to do this?
Finally, I found an article that has described three steps to do that, and I thought that may be a through answer:
Create a custom serializer extending the StdSerializer class
Create an object of SimpleModule class, adding to it the custom serializer and specifying for which class it must be used
Register the module on the ObjectMapper instance
ref: Jackson: create and register a custom JSON serializer with StdSerializer and SimpleModule classes
In my application the JAXB output generates like:
this.marshalOut(jaxb_Object, fileOutputStream);
this is method call to the spring Object XML Mapping Marshallers that generate XML files. Now, I also like to generate JSON files after this line. Any one have idea about generating JSON output using JAXB input.
I found this example code online:
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
// make deserializer use JAXB annotations (only)
mapper.getDeserializationConfig().setAnnotationIntrospector(introspector);
// make serializer use JAXB annotations (only)
mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
mapper.writeValue( outputStream, jaxb_object);
The setAnnotationIntrospector is deprecated, is there any other way of solving this problem?
The following works (and does not use any deprecated constructors) :
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector =
new JaxbAnnotationIntrospector(mapper.getTypeFactory());
mapper.setAnnotationIntrospector(introspector);
Specifically, this line
new JaxbAnnotationIntrospector(mapper.getTypeFactory());
uses a non-deprecated constructor. I've tested this and it successfully processes JAXB Annotations (such as #XmlTransient, in my case).
You can use jackson-module-jaxb-annotations as stated in the doc you can register a JaxbAnnotationModule module:
JaxbAnnotationModule module = new JaxbAnnotationModule();
// configure as necessary
objectMapper.registerModule(module);
Doing so you can now use both JAXB annotation and Jackson native annotation.
If you update Jackson to 2.0 it is not deprecated:
http://fasterxml.github.com/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/ObjectMapper.html
You can see my configuration here (Spring):
Registrer MappingJackson2HttpMessageConverter in Spring 3.1.2 with JAXB annotations
The correct solution for me was:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector());
According to the Jackson javadoc:
setAnnotationIntrospector
#Deprecated
public final void setAnnotationIntrospector(AnnotationIntrospector ai)
Deprecated. Since 1.8, use either withAnnotationIntrospector(AnnotationIntrospector) or Module API instead
Method for replacing existing annotation introspector(s) with specified introspector. Since this method modifies state of configuration object directly, its use is not recommended
Did you check the method withAnnotationIntrospector(AnnotationIntrospector ai) to see wheter or not it's useful in your case?
It seems the standard approach for deserializing JAXB XML is to specify the package name when creating the context. Then, JAXB looks up the class based on the root element:
JAXBContext jc = JAXBContext.newInstance("com.foo");
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal(new StringReader("<?xml version="1.0" encoding="UTF-8" standalone="yes"?><MyJaxb>..."));
I'm looking for a more flexible approach where I don't have to specify the package name and could still deserialize any object. This would be as simple as JAXB storing the package in the XML, but I can't seem to find out how to do this. I can write the code to do it myself but that would be unpleasant. It would like JAXB to do it, if possible. BTW, I am not using schemas, just Annotations and marshal/unmarshal. Any ideas?
Actually you can not deserialize "any" object with pure JAXB. You have to specify either packages (where ObjectFactory.class will be sought) or list of classes like JAXBContext.newInstance(Class1.class, Class2.class, Class3.class); That's how jaxb works, it's a part of agreement.
If your tasks are wider that that, e.g. building java classes from arbitrary xml data structure - it's also possible, but you have to be a bit more concrete - what do you mean under "more flexible approach".
You should be able to add more than one package when you get the instance of the jaxbcontext object. You can add as many packages as you want like below.
JAXBContext jc = JAXBContext.newInstance("com.foo.package1:com.foo.package2" );
however, I am not sure how you are gonna use it if you deserialize it into an Object instance?
Are you not gonna use what you have just deserialized?
Also Unmarshaller is not a thread safe class if your application is a multithreaded one.
I have my own domain model and corresponding XSD schema for it. It consists of data types and messages that are exchanged in my application. I use XJC tool from Java JRE 1.5 for generation of Java classes for the given XSD schema. The generated classes do not contain neither the serialization/deserialization method nor the validation code. How can I achieve this using JAXB?
Regards
Are you using JAXB 1.x or 2.x?
If 2.x then validation is built in. See this article.
Do you mean that you just want the code to marshall the Bean to XML and unmarshall the XML to a Bean?
There are many articles that show this. Here's an example of marshalling a bean into xml:
JAXBContext jaxb = JAXBContext.newInstance(MyBean.class);
Marshaller marshaller = jaxb.createMarshaller();
java.io.StringWriter sw = new StringWriter();
marshaller.marshal(myBean, sw);
System.out.println(sw.toString());