1

I have a JSON object like

{
  "id" : "1",
  "children" : ["2","3"]
}

And I have a Java object like (constructor, getters and setters are omitted):

public class Entity {
    public String id;
    public String children;
}

I want this JSON to be deserialized to my Java object by this code using Jackson:

Entity entity = mapper.readValue(json, Entity.class);

But get the following error:

Can not deserialize instance of java.lang.String out of START_ARRAY token

How can I solve it without changing type of children field?

The children field is expected to have the following value: ["2","3"].

6
  • Could you change the type of children to List<String>? Commented Jan 24, 2017 at 9:50
  • how do you want to store "children":["2","3"] if you dont want to change type ?? you want only first value ? Commented Jan 24, 2017 at 9:53
  • I want something like "["2","3"]" (quotes can be with backslashes) Commented Jan 24, 2017 at 9:55
  • so you need to send json like "children":"[2,3]" , if you can, otherwise you'd need create and register custom mapper Commented Jan 24, 2017 at 9:56
  • 1
    I don't think you can do it with standard mapper, write custom mapper Commented Jan 24, 2017 at 10:00

3 Answers 3

2

Creating a custom deserializer

Create a custom deserializer to get the raw JSON value. You can choose one of the following implementations, according to your needs:

  1. It will give you the JSON as is, that is, keeping all the spaces and tabs:
public class RawJsonDeserializer extends JsonDeserializer<String> {

    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt)
           throws IOException, JsonProcessingException {

        long begin = jp.getCurrentLocation().getCharOffset();
        jp.skipChildren();
        long end = jp.getCurrentLocation().getCharOffset();

        String json = jp.getCurrentLocation().getSourceRef().toString();
        return json.substring((int) begin - 1, (int) end);
    }
}
  1. It will give you the JSON without extra spaces and tabs:
public class RawJsonDeserializer extends JsonDeserializer<String> {

    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt)
           throws IOException {

        JsonNode node = jp.getCodec().readTree(jp);
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        return mapper.writeValueAsString(node);
    }
}

Annotate your class to use the deserializer defined above

Change the Entity class by annotating the children attribute with @JsonDeserialize referencing the deserializer defined above:

public class Entity {

    public String id;

    @JsonDeserialize(using = RawJsonDeserializer.class)
    public String children;
}

Parsing the JSON

Then parse the JSON using ObjectMapper and Jackson will use your custom deserializer:

String json = "{\"id\":\"1\",\"children\":[\"2\",\"3\"]}";

ObjectMapper mapper = new ObjectMapper();
Entity entity = mapper.readValue(json, Entity.class);

The value of the children attribute will be ["2","3"].


For more details, have a look at this question.

Sign up to request clarification or add additional context in comments.

Comments

1

Marshall your objects into JSON format.
Then Unmarshall from the JSON file

public interface MarshallingSupport {
public String marshal(Object object);
public <T> T unmarshal(String s, Class<T> t);
}

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class JacksonJSONMarshallingSupport implements MarshallingSupport {

private final ObjectMapper mapper;

   public JacksonJSONMarshallingSupport(ObjectMapper mapper) {
       this.mapper = mapper;
       this.mapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
   }

    @Override
    public String marshal(Object object) {
       try {
            return mapper.writeValueAsString(object);
           } catch (JsonProcessingException ex) {
               throw new RuntimeException(ex);
           }
   }

   @Override
   public <T> T unmarshal(String s, Class<T> t) {
       try {
             T newObj = mapper.readValue(s, t);
             return newObj;
           } catch (IOException ex) {
               throw new RuntimeException(ex);
           }
   }
}

Comments

1

Taking the @Cassio's answer and if you don't want to or you can't annotate your Entity class, just add some configurations.

First create an abstract class [for method annotation purpose you can create an interface, but in this case we will annotate a bean property so we create an abstract class, and if you also want to annotate a method in this abstract class you have to declare that method as abstract] that will be like a mime bean for Jackson configurations:

public abstract class EntityMixIn {

    @JsonDeserialize(using = RawJsonDeserializer.class)
    public String children;

}

Now, you have to tell your mapper to take this mixin class and act like the original Entity class just for this configuration purpose:

mapper.addMixIn(Entity.class, EntityMixIn.class);

4 Comments

Jackson mix-in annotation is a great resource when modifying your classes is not an option. However saying that the mix-in interface will behave like the original Entity is not accurate. You can think of mix-in annotations as a kind of aspect-oriented way of adding more annotations during runtime to augment the statically defined ones.
Yeap! you are right, but it is just for the example and that's why previously I said that it will be like a mime bean, but I will update this affirmation. Thank you.
I've upvoted your answer. I think it's a nice contribution to the solution I had provided :)
Thank you @Cassio. I also clarified the abstract class purpose.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.