Jackson Serialization to Array - json

I have the following class:
class People
{
private List<String> people = new ArrayList<>();
public People()
{
people.add("Jhon");
people.add("Rose");
}
}
it is serialized using jackson to {"people":["Jhon","Rose"]}
I would like to serialize to ["Jhon","Rose"] without custom serializers.
any suggestion?
any help will be appreciated!

The simplest way would be to get the field and serialize that instead of the wrapper object:
People people = new People();
String json = mapper.writeValueAsString(people.getPeople());
If that's not an option, a Converter may be simpler than a custom serializer:
class PeopleToList extends StdConverter<People, List<String>> {
#Override public List<String> convert(People people) {
return people.getPeople();
}
}
and specify to use that:
#JsonSerialize(converter = PeopleToList.class)
class People {

Related

How to deserialize single json property into multiple Java fields (if possible with converter)

Having this class:
#Getter
#Setter
public class Result {
private String positionText;
private Integer positionNumber;
.. many many other properties ..
}
and deserializing this json:
[
{
"position": "1",
.. many many other properties ..
},
{
"position": "FOO",
.. many many other properties ..
},
..
}
how can the position json property deserialized into both the positionText and positionNumber Java fields?
public abstract class ResultMixIn {
#JsonProperty("position")
abstract String getPositionText();
#JsonProperty("position")
abstract Integer getPositionNumber();
}
but this gives a:
Conflicting getter definitions for property "position": com.example.domain.Result#getPositionText() vs com.example.domain.Result#getPositionNumber()
Also changing the abstract getters to setters does not make a difference.
If possible I would like to avoid a fully fledged ResultDeserializer extending StdDeserializer as the Result class has many more properties which I would prefer not to deserialize "by hand".
PS: I'm not concerned about serializing. I'm only deserializing the model.
First you need to annotate the properties of the Result class,
so that Jackson will deserialize the positionText property,
but not the positionNumber.
You will do the latter by yourself in a taylor-made deserializer.
#Getter
#Setter
public class Result {
#JsonProperty("position")
private String positionText;
#JsonIgnore
private Integer positionNumber;
.. many many other properties ..
}
By default Jackson would use a BeanDeserializer for deserializing Result objects.
But you want a slightly modified implementation of this deserializer.
The rest of this answer is largely an adaptation of the accepted answer given to
the question How do I call the default deserializer from a custom deserializer in Jackson.
As usual your deserializer extends from StdDeserializer<Result>,
but it also implements the ResolvableDeserializer interface.
In the deserialize method most of the work is delegated to the default deserializer
(in this case a BeanDeserializer) which we got from Jackson.
We only add a small extra logic for setting the positionNumber property
based on the positionText property.
public class ResultDeserializer extends StdDeserializer<Result> implements ResolvableDeserializer {
private final JsonDeserializer<?> defaultDeserializer;
public ResultDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(Result.class);
this.defaultDeserializer = defaultDeserializer;
}
#Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
if (defaultDeserializer instanceof ResolvableDeserializer) {
// We need to resolve the default deserializer, or else it won't work properly.
((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
}
}
#Override
public Result deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// let defaultDeserializer do the work:
Result result = (Result) defaultDeserializer.deserialize(p, ctxt);
// here you do your custom logic:
String positionText = result.getPositionText();
if (positionText != null) {
try {
result.setPositionNumber(Integer.valueOf(positionText));
} catch(NumberFormatException e) {
// positionText is not a valid integer
}
}
return result;
}
}
Finally you need to tell Jackson that you want the above ResultDeserializer
to be used for deserializing Result objects.
This is done by the following customization of the ObjectMapper,
which will wrap your ResultDeserializer around Jackson's
default deserializer, only if a Result object is to be deserialized:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new SimpleModule()
.setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (Result.class == beanDesc.getBeanClass())
return new ResultDeserializer(deserializer); // your deserializer
return deserializer;
}
}));
Then you can deserialize your JSON content as usual, for example:
File file = new File("example.json");
List<Result> results = objectMapper.readValue(file, new TypeReference<List<Result>>() {});

Is it possible to pass a java.util.Stream to Gson?

I'm currently working on a project where I need to fetch a large amount of data from the Database and parse it into a specific Json format, I already have built my custom Serializers and Its working properly when i pass a List to Gson. But as I was already working with Streams from my JPA Layer, I thought I could pass the Stream down to the Gson parser so that it could transform it directly to my Json data. But I'm getting an empty Json object instead of a correctly populated one.
So, if anyone could point to me a way to make Gson work with Java 8 Streams or if this isn't possible currently.. i could not find anything on Google, so i came to Stackoverflow.
You could use JsonWriter to streaming your data to output stream:
public void writeJsonStream(OutputStream out, Stream<DataObject> data) throws IOException {
try(JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"))) {
writer.setIndent(" ");
writer.beginArray();
data.forEach(d -> {
d.beginObject();
d.name("yourField").value(d.getYourField());
....
d.endObject();
});
writer.endArray();
}
}
Note that you're in charge of controling the json structure.
That is, if your DataObject contains nested Object, you have to write beginObject()/endObject() respectively. The same goes for nested array.
It is not as trivial as one would expect, but it can be done in a generic way.
When you look into the Javadoc to TypeAdapterFactory, they provide a very simplistic way of writing a TypeAdapterFactory for a custom type. Alas, it does not work as expected because of problems with element type detection. The proper way to do this can be found in Gson-internal CollectionTypeAdapterFactory. It is quite complex, but taking what's necessary one can come up with something like that:
final class StreamTypeAdapterFactory implements TypeAdapterFactory {
#SuppressWarnings("unchecked")
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType();
if (!Stream.class.isAssignableFrom(rawType)) {
return null;
}
Type elementType = ExtraGsonTypes.getStreamElementType(type, rawType);
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
return (TypeAdapter<T>) new StreamTypeAdapter<>(elementAdapter);
}
private static class StreamTypeAdapter<E> extends TypeAdapter<Stream<E>> {
private final TypeAdapter<E> elementAdapter;
StreamTypeAdapter(TypeAdapter<E> elementAdapter) {
this.elementAdapter = elementAdapter;
}
public void write(JsonWriter out, Stream<E> value) throws IOException {
out.beginArray();
for (E element : iterable(value)) {
elementAdapter.write(out, element);
}
out.endArray();
}
public Stream<E> read(JsonReader in) throws IOException {
Stream.Builder<E> builder = Stream.builder();
in.beginArray();
while (in.hasNext()) {
builder.add(elementAdapter.read(in));
}
in.endArray();
return builder.build();
}
}
private static <T> Iterable<T> iterable(Stream<T> stream) {
return stream::iterator;
}
}
The ExtraGsonTypes is a special class that I used to circumvent package-private access to $Gson$Types.getSupertype method. It's a hack that works if you're not using JDK 9's modules - you simply place this class in the same package as $Gson$Types:
package com.google.gson.internal;
import java.lang.reflect.*;
import java.util.stream.Stream;
public final class ExtraGsonTypes {
public static Type getStreamElementType(Type context, Class<?> contextRawType) {
return getContainerElementType(context, contextRawType, Stream.class);
}
private static Type getContainerElementType(Type context, Class<?> contextRawType, Class<?> containerSupertype) {
Type containerType = $Gson$Types.getSupertype(context, contextRawType, containerSupertype);
if (containerType instanceof WildcardType) {
containerType = ((WildcardType)containerType).getUpperBounds()[0];
}
if (containerType instanceof ParameterizedType) {
return ((ParameterizedType) containerType).getActualTypeArguments()[0];
}
return Object.class;
}
}
(I filed an issue about that in GitHub)
You use it in the following way:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new StreamTypeAdapterFactory())
.create();
System.out.println(gson.toJson(Stream.of(1, 2, 3)));

Trouble getting desired json output with JacksonJaxbJsonProvider

I'm using the latest Jackson (2.2.3) with a CXF application.
Here is my Jackson provider:
public class CustomJacksonJsonProvider extends JacksonJaxbJsonProvider {
public CustomJacksonJsonProvider() {
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
JaxbAnnotationModule jaxbModule = new JaxbAnnotationModule();
mapper.registerModule(jaxbModule);
this._mapperConfig.setMapper(mapper);
}
}
I have the following annotated class.
#XmlType(name = "configInfo")
#XmlRootElement(name = "configInfo")
public class ConfigInfo {
#XmlElement(name = "foo")
private String foo;
#XmlElementWrapper(name = "devices")
#XmlElement(name = "device")
private List<Device> devices;
public final List<Device> getDevices() {
if (devices == null)
devices = new ArrayList<Device>();
return devices;
}
}
I created an instance with no "foo" value, and one device in the devices list. When I render this, I get the following:
{"device":[{"name":"abc","type":"def"}]}
How can I make "device" render as "devices"?
I've managed to figure this out. The key realization is that if the JAXB annotations are confusing Jackson, then perhaps I should just have Jackson ignore them. I simply removed the registration of the "JaxbAnnotationModule" and now both my JSON and XML output are sane. I now need to consider whether it makes any sense to use "JacksonJaxbJsonProvider" as opposed to a simpler provider.

GSON deserialization problem

I am having a deserialization problem using the GSON library.
The following is the JSON code which I try to deserialize
{"response": {
"#service": "CreateUser",
"#response-code": "100",
"#timestamp": "2010-11-27T15:52:43-08:00",
"#version": "1.0",
"error-message": "",
"responseData": {
"user-guid": "023804207971199"
}
}}
I create the following classes
public class GsonContainer {
private GsonResponse mResponse;
public GsonContainer() { }
//get & set methods
}
public class GsonResponse {
private String mService;
private String mResponseCode;
private String mTimeStamp;
private String mVersion;
private String mErrorMessage;
private GsonResponseCreateUser mResponseData;
public GsonResponse(){
}
//gets and sets method
}
public class GsonResponseCreateUser {
private String mUserGuid;
public GsonResponseCreateUser(){
}
//get and set methods
}
After calling the GSON library the data is null. Any ideas what is wrong with the classes?
Thx in advance for your help ... I assume it's something trivial ....
#user523392 said:
the member variables have to match exactly what is given in the JSON response
This is not the case.
There are a few options for specifying how Java field names map to JSON element names.
One solution that would work for the case in the original question above is to annotate the Java class members with the #SerializedName to very explicitly declare what JSON element name it maps to.
// output: [MyObject: element=value1, elementTwo=value2]
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
public class Foo
{
static String jsonInput =
"{" +
"\"element\":\"value1\"," +
"\"#element-two\":\"value2\"" +
"}";
public static void main(String[] args)
{
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
MyObject object = gson.fromJson(jsonInput, MyObject.class);
System.out.println(object);
}
}
class MyObject
{
String element;
#SerializedName("#element-two")
String elementTwo;
#Override
public String toString()
{
return String.format(
"[MyObject: element=%s, elementTwo=%s]",
element, elementTwo);
}
}
Another approach is to create a custom FieldNamingStrategy to specify how Java member names are translated to JSON element names. This example would apply the same name mapping to all Java member names. This approach would not work for the original example above, because not all of the JSON element names follow the same naming pattern -- they don't all start with '#' and some use camel case naming instead of separating name parts with '-'. An instance of this FieldNamingStrategy would be used when building the Gson instance (gsonBuilder.setFieldNamingStrategy(new MyFieldNamingStrategy());).
class MyFieldNamingStrategy implements FieldNamingStrategy
{
// Translates the field name into its JSON field name representation.
#Override
public String translateName(Field field)
{
String name = field.getName();
StringBuilder translation = new StringBuilder();
translation.append('#');
for (int i = 0, length = name.length(); i < length; i++)
{
char c = name.charAt(i);
if (Character.isUpperCase(c))
{
translation.append('-');
c = Character.toLowerCase(c);
}
translation.append(c);
}
return translation.toString();
}
}
Another approach to manage how Java field names map to JSON element names is to specify a FieldNamingPolicy when building the Gson instance, e.g., gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);. This also would not work with the original example, however, since it applies the same name mapping policy to all situations.
The JSON response above cannot be deserialized by GSON because of the special characters # and -. GSON is based on reflections and the member variables have to match exactly what is given in the JSON response.

How to reuse Jersey's JSON/JAXB for serialization?

I have a JAX-RS REST service implemented using Jersey. One of the cool features of JAX-RS/Jersey is how easily a POJO can be turned into a REST service, simply by sprinkling a few Java annotations... including a trivially easy mechanism for translating POJOs to JSON - using JAXB annotations.
Now, I'd like to be able to take advantage of this cool JSON-ifying functionality for non-REST purposes - I'd love to be able to just serialize some of these objects to disk, as JSON text. Here's an example JAXB object that I'd want to serialize:
#XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {
public UserInfoImpl() {}
public UserInfoImpl(String user, String details) {
this.user = user;
this.details = details;
}
public String getUser() { return user; }
public void setUser(String user) { this.user = user; }
public String getDetails() { return details; }
public void setDetails(String details) { this.details = details; }
private String user;
private String details;
}
Jersey can turn one of these into json with no additional info. I'm wondering if Jersey has exposed this functionality in the API for needs like mine? I've had no luck finding it so far...
Thanks!
UPDATE 2009-07-09: I have learned that I can use the Providers object to almost do exactly what I want:
#Context Providers ps;
MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
uw.writeTo(....)
... This writes the object as json to any outputstream, which would be perfect for me, but I can only get at the Providers object using #Context from a #Component object. Does anyone know how to access it from a regular, un-annotated POJO? Thanks!
Jersey uses a couple different frameworks depending on whether you use mapped(), badgerfish(), or natural() notation. Natural is usually the one people want. And that's implemented using the very good (and very fast) standalone Jackson JSON processor, I believe, which goes from Object->JAXB->JSON. However Jackson also provides it's own JAX-RS provider to go direct Object->JSON.
In fact, they even added support for JAXB annotations. Have a look at
http://wiki.fasterxml.com/JacksonJAXBAnnotations
I think that's ultimately what you are looking for. Jackson does Object<->JSON processing...Jersey just makes the calls for you
Here's a simple brief example of using JAXB to map objects to JSON (using Jackson):
http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-jackson-howto.texy
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
JAXB annotations work fine when serializing to XML.
The main problem is that JAXB does not support empty arrays. So when serializing something like this...
List myArray = new ArrayList();
...to json via jaxb anottations all your empty arrays become null instead of [].
To solve this you can just serialize your pojos directly to json via jackson.
Take a look at this from Jersey's user guide:
http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959
This is the best way to use Jackson provider without JAXB. Moreover, you can always use the latest version of jackson by downlaoding jackson-all-x.y.z-jar from its web.
This method will not interfere with your jaxb annotations so I would suggest to have a try!
Since Jersey is a reference implementation of JAX-RS and JAX-RS is focused completely on providing a standard way of implementing the end-point for the REST service the issues of serializing the payload is left to other standards.
I think that if they included object serialization in the JAX-RS standard it would quickly become a large multi-headed beast that would be difficult to implement and loose some of it's focus.
I appreciate how focused Jersey is on delivering clean and simple to use REST endpoints. In my case I've just subclassed a parent that has all the JAXB plumbing in it so marshalling objects between binary and XML is very clean.
With a little Jersey specific bootstrapping, you can use it to create the necessary JSON objects for you. You need to include the following dependencies (you can use bundle, but it will cause problems if you are using Weld for testing):
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.12</version>
</dependency>
From there you can create a JAXB annotated class. The following is an example:
#XmlRootElement
public class TextMessage {
private String text;
public String getText() { return text; }
public void setText(String s) { this.text = text; }
}
Then you can create the following unit test:
TextMessage textMessage = new TextMessage();
textMessage.setText("hello");
textMessage.setUuid(UUID.randomUUID());
// Jersey specific start
final Providers ps = new Client().getProviders();
// Jersey specific end
final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {
#Override
public void add(final String key, final Object value) {
}
#Override
public void clear() {
}
#Override
public boolean containsKey(final Object key) {
return false;
}
#Override
public boolean containsValue(final Object value) {
return false;
}
#Override
public Set<java.util.Map.Entry<String, List<Object>>> entrySet() {
return null;
}
#Override
public List<Object> get(final Object key) {
return null;
}
#Override
public Object getFirst(final String key) {
return null;
}
#Override
public boolean isEmpty() {
return false;
}
#Override
public Set<String> keySet() {
return null;
}
#Override
public List<Object> put(final String key, final List<Object> value) {
return null;
}
#Override
public void putAll(
final Map<? extends String, ? extends List<Object>> m) {
}
#Override
public void putSingle(final String key, final Object value) {
}
#Override
public List<Object> remove(final Object key) {
return null;
}
#Override
public int size() {
return 0;
}
#Override
public Collection<List<Object>> values() {
return null;
}
};
final MessageBodyWriter<TextMessage> messageBodyWriter = ps
.getMessageBodyWriter(TextMessage.class, TextMessage.class,
new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
Assert.assertNotNull(messageBodyWriter);
messageBodyWriter.writeTo(textMessage, TextMessage.class,
TextMessage.class, new Annotation[0],
MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
final String jsonString = new String(baos.toByteArray());
Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));
The advantage to this approach is it keeps everything within the JEE6 API, no external libraries are explicitly needed except for testing and getting the providers. However, you need to create an implementation of MultivaluedMap since there is nothing provided in the standard and we don't actually use it. It may also be slower than GSON, and a lot more complicated than necessary.
I understand XML views but it would have shown some foresight to require JSON support for POJOs as standard equipment. Having to doctor up JSON identifiers with special characters makes no sense if your implementation is JSON and your client is a JavaScript RIA.
Also, not that Java Beans are NOT POJOs. I would like to use something like this on the outer surface of my web tier:
public class Model
{
#Property height;
#Property weight;
#Property age;
}
No default constructor, no getter/setter noise, just a POJO with my own annotations.