0

The object I want to cast into looks like

public class AdDimension {
    private int width;
    private int height;

    public AdDimension() {
        // needed by Jackson
    }

    public AdDimension(final int width, final int height) {
        this.width = width;
        this.height = height;
    }
..
}

and it is used inside

public class Campaign {
    private String id;
    private List<AdDimension> adDimensions;

    public Campaign() {
        // needed by Jackson
    }
 ...
}

I try to deserialize in test as

@Test
public void testLoadCampaigns() throws IOException {
    final File campaignsFile = new File(getClass().getClassLoader().getResource("campaigns.json").getFile());
    final List<Campaign> campaigns = new JsonReader().loadCampaigns(campaignsFile);
    System.out.println(campaigns);
}

and my campaigns file look like

[
  {
    "id": 1,
    "targetedCountries": ["CA", "IT"],
    "targetedDomain": "apple.com",
    "adDimensions": [[300,250], [600,200]]
  }
]

When I run my test, I see

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.org.site.messages.AdDimension out of START_ARRAY token
 at [Source: /Users/harit/IdeaProjects/site/target/test-classes/campaigns.json; line: 6, column: 22] (through reference chain: java.util.ArrayList[0]->com.org.scout.messages.Campaign["adDimensions"]->java.util.ArrayList[0])
    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.DeserializationContext.mappingException(DeserializationContext.java:853)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromArray(BeanDeserializerBase.java:1257)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:157)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:217)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:101)
    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.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:217)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3736)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2639)
    at com.org.harness.JsonReader.loadCampaigns(JsonReader.java:15)
    at com.org.harness.JsonReaderTest.testLoadCampaigns(JsonReaderTest.java:17)
    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:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    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:497)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)


Results :

Tests in error: 
  testLoadCampaigns(com.org.harness.JsonReaderTest): Can not deserialize instance of com.org.site.messages.AdDimension out of START_ARRAY token(..)

How can I read [[300,250], [600,200]] into List<AdDimension>?

2
  • stackoverflow.com/q/6349421/1743880 Commented Nov 28, 2015 at 17:26
  • 1
    Define a custom deserializer for your dimension class than parses an array with two elements. Commented Nov 28, 2015 at 17:28

2 Answers 2

3

Jackson, by default, attempts to deserialize JSON array values into either Java array types or Collection types (eg. ArrayList). But you're trying to make it deserialize a JSON array like [600,200] into a AdDimension object. This won't work out of the box.

You can change your JSON like other answers have suggested or you use a custom deserialization strategy.

Your first option is to define a custom JsonDeserializer (though you should use its sublcass StdDeserializer)

class AdDimensionDeserializer extends JsonDeserializer<AdDimension> {
    @Override
    public AdDimension deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        // you have complete control over the tokens in the JSON, so validate as you wish
        ArrayNode arrayNode = parser.readValueAsTree();
        return new AdDimension(arrayNode.get(0).asInt(), arrayNode.get(1).asInt());
    }
}

and register it as

@JsonDeserialize(using = AdDimensionDeserializer.class)
class AdDimension {

Jackson will instantiate AdDimensionDeserializer and use the instance to deserialize the JSON array elements into an instance(s) of AdDimension.

Another option is to use @JsonCreater

Marker annotation that can be used to define constructors and factory methods as one to use for instantiating new instances of the associated class.

For example

@JsonCreator
public AdDimension(int[] dimensions) {
    // again, validate as required
    this.width = dimensions[0];
    this.height = dimensions[1];
}

Jackson will find this constructor and use it to deserialize your JSON. It will first attempt to deserialize the text [300,250] into a int[], which it obviously can, and then pass that to your constructor.

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

Comments

1

Maybe is a bad json format??

I think it should be like this

[
  {
    "id": 1,
    "targetedCountries": ["CA", "IT"],
    "targetedDomain": "apple.com",
    "adDimensions": [{"width":300, "height":250}, {"width":600, "height":200}]
  }
]

I can´t test it now, but it seems to be no OK.

Comments

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.