2

I am trying to use Jackson with fasterxml (vs codehaus) to get some data I store in mongoDb deserialized. The query is returning the proper json string, but I keep getting this error what we try to convert it to an object:

Can not deserialize instance of java.lang.String out of START_OBJECT token Properties("property1")

Class :

    package com.sharecare.service.segment;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.jamconsultg.jamplatform.domain.segmentation.Segment;

import java.util.List;
import java.util.Properties;

/**
 * Created by wawada on 1/15/16.
 */

public class SubSkyScraper{

    @JsonProperty("_id")
    private String id;

    private String name;

    private Properties properties;

    @JsonProperty("_segments")
    private List<Segment> segments;

    public SubSkyScraper() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public List<Segment> getSegments() {
        return segments;
    }

    public void setSegments(List<Segment> segments) {
        this.segments = segments;
    }
}

Test :

    package com.sharecare.service.segment;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jamconsultg.jamplatform.domain.segmentation.Segment;
import com.sharecare.segment.SkyScraper;
import org.junit.Test;

import java.io.IOException;
import java.util.List;
import java.util.Properties;

/**
 * Created by wawada on 1/15/16.
 */


public class ObjectMapperTest {

    @Test
    public void testGettingTheObject(){

        String json = "{\n" +
                "\"_id\": \"objectid\" ,\n" +
                "\"_segments\" : [ \"global\"] , \n" +
                "\"name\" : \"sc\" , \n" +
                "\"properties\" : { \n" +
                "    \"property1\": {\n" +
                "        \"property2\" : \"value1\"\n" +
                "    },\n" +
                "    \"property3\" : { \"property4\": \"value2\"} , \n" +
                "    \"property5\": {\n" +
                "        \"property6\" : { \n" +
                "                    \"property7\": \"value3\" , \n" +
                "                    \"property8\": \"value4\"\n" +
                "    }\n" +
                "}\n" +
                "}";


        ObjectMapper objectMapper = new ObjectMapper();
        try {
            objectMapper.readValue(json, SubSkyScraper.class);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }




}

output :

    com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: {
"_id": "objectid" ,
"_segments" : [ "global"] , 
"name" : "sc" , 
"properties" : { 
    "property1": {
        "property2" : "value1"
    },
    "property3" : { "property4": "value2"} , 
    "property5": {
        "property6" : { 
                    "property7": "value3" , 
                    "property8": "value4"
    }
}
}; line: 6, column: 5] (through reference chain: com.sharecare.service.segment.SubSkyScraper["properties"]->java.util.Properties["property1"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:857)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:62)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringMap(MapDeserializer.java:495)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:341)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:95)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:258)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3736)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2726)
    at com.sharecare.service.segment.ObjectMapperTest.testGettingTheObject(ObjectMapperTest.java:43)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

The json saved in mongodb is structures as follows :

{
"_id": "objectid" ,
"_segments" : [ "global "] , 
"name" : "sc" , 
"properties" : { 
    "property1": {
        "property2" : "value1"
    },
    "property3" : { "property4": "value2"} , 
    "property5": {
        "property6" : { 
                    "property7": "value3" , 
                    "property8": "value4"
    }
}
}

How can I get Jackson to deserialize the properties properly?

PS: This worked flawlessly with codehaus

Wael Awada
  • 1,506
  • 3
  • 18
  • 31
  • This question is similar to http://stackoverflow.com/questions/19389723/can-not-deserialize-instance-of-java-lang-string-out-of-start-object-token Hope that helps. – Anvesh Vejandla Jan 14 '16 at 20:06
  • We already have the class skyscraper looking from the skyscraper collection. We have the various variables setup. I do not see how it is similar to be honest. Can you elaborate? – Wael Awada Jan 14 '16 at 20:27
  • i found this to be similar when i check your json. Basically trying to deserialize a json in a json using Jackson. This is not possible as stated by [Sotirios Delimanolis](http://stackoverflow.com/users/438154/sotirios-delimanolis) in the link i pasted earlier. He mentioned in detail an approach. I probably thinking you need to mention @JsonProperty("_properties) for properties. I haven't tried a POC yet but i strongly believe that might be the case. – Anvesh Vejandla Jan 14 '16 at 20:40
  • the name in mongodb for the properties variable is properties not _properties. We have _segments that we are using the @JsonProperty annotation for, – Wael Awada Jan 14 '16 at 21:00
  • Make sure that annotations you use with Jackson 2.x are those defined for Jackson 2.x (that is, both mapper and annotation packages are from `com.fasterxml.jackson`). Number one problem with upgrade is that Jackson 1.x annotations are accidentally still used. – StaxMan Jan 15 '16 at 01:35
  • Can you try feeding the json string by escaping all double quotes and then surrounding all your data in double quotes ? What i mean is - can you try feeding "{"a":"b", "c":"d"}" as "{\"a\":\"b\", \"c\":\"d\"}" – Gyan Jan 15 '16 at 09:24
  • Can you show your properties class? – Patrick Jan 15 '16 at 16:22
  • @Patrick its java.util.Properties – Wael Awada Jan 15 '16 at 17:27
  • @StaxMan I verified that. Everything is through fasterxml – Wael Awada Jan 15 '16 at 17:27

1 Answers1

0

here is my approach:

I'm using custom deserializer like below:

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

public class PropertiesDeserializer extends StdDeserializer<Properties> {
    private static final long serialVersionUID = 2743004642083542567L;

    public PropertiesDeserializer() { 
        this(null); 
    } 

    public PropertiesDeserializer(Class<?> vc) { 
        super(vc); 
    }

    @Override
    public Properties deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonDeserializer<Object> mapDeserializer = findDeserializer(ctxt, ctxt.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class), null);
        @SuppressWarnings("unchecked")
        Map<String,Object> rawValue = (Map<String, Object>) mapDeserializer.deserialize(jp, ctxt);
        if (rawValue == null) {
            return null;
        }
        Properties mappedValue = new Properties();
        rawValue.forEach((key, value) -> mappedValue.put(key, value));
        return mappedValue;
    }

}

and then register it in your ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(Properties.class, new PropertiesDeserializer());
mapper.registerModule(simpleModule);

If you want to parse nested java.util.Properties you can do it in deserialize method while iterating through rawValue map

Kuba Samczuk
  • 111
  • 6