1

EDIT: by request of some of you I'm posting my real data structures and classes. I failed in trying to make it easier for you to understand the problem.

I have a problem in resolving with Jackson null JSON array elements, ending up with an exception that I'll report later in this post.

I have a long-winded JSON string coming from a 3rd party provider:

[ null, null, [ { "t" : { "id" : 0, "it" : "Attuazione" }, "c" : "DM.10.0.2", "l" : "Macro 2", "v0" : 0, "scid" : "1", "m" : "10", "sam" : 0, "v1" : 100, "smcm" : true, "w" : "OD.10.4", "st" : { "auto_formula" : { "ia" : "($x > 0 ? 1 : 0)", "id" : "($x > 0 ? 1 : 0)", "bit" : "($x > 0 ? 1 : 0)", "oa" : "($x > 0 ? 1 : 0)", "od" : "($x > 0 ? 1 : 0)", "dm" : "($x > 0 ? 1 : 0)" }, "id" : 0, "css_rule" : "containerTypeOnOff", "default_measure_unit" : null, "it" : "On \/ Off", "widget" : { "id" : 0, "caption" : { "it" : "Etichetta di testo" } } } } ], null, null, null, null, null ] 

My Java classes ensemble is the following.

This is the outmost container:

public class TinyMap { ArrayList<TinyMapModule> modules; public TinyMap() { ... } public ArrayList<TinyMapModule> getModules() { ... } /** * @param modules the modules to set */ @SuppressWarnings("unchecked") public void setModules(ArrayList<TinyMapModule> modules) { ... } public void appendNewMacro(TinyMapModule m) { ... } } 

And this is the first-level container:

public class TinyMapModule { private ArrayList<TinyMapMacro> macros; /** * C'tor */ public TinyMapModule() { ... } /** * @return ArrayList<TinyMapMacro> */ public ArrayList<TinyMapMacro> getMacros() { ... } /** * @param macros the macros to set */ @SuppressWarnings("unchecked") public void setMacros(ArrayList<TinyMapMacro> macros) { ... } } 

And this is the innermost level:

public class TinyMapMacro { private String c; private String l; private String m; private MacroType t; private String w; private static Logger logger; static { logger = Logger.getLogger(TinyMapMacro.class); DOMConfigurator.configure("log4j.xml"); } /** * C'tor */ public TinyMapMacro() { ... } public static class MacroType { private int id; private String it; // Italian public int getId() { ... } public void setId(int id) { ... } public String getIt() { ... } public void setIt(String it) { ... } } public String getC() { ... } public void setC(String c) { ... } public String getL() { ... } public void setL(String l) { ... } public String getM() { ... } public void setM(String m) { ... } public MacroType getT() { ... } public void setT(MacroType t) { ... } public String getW() { ... } public void setW(String w) { ... } public int getTypeId() { ... } public String getLocalizedTypeString() { ... } } 

Finally, this is my deserialization code:

ObjectMapper mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); ObjectReader reader = mapper.reader(TinyMapModule.class); try { logger.info("Instantiating ObjectMapper"); TinyMap tm = new TinyMap(); tm.buildTinyMap(reader.readValues(jsonString.replaceAll("null", "[{\"name\":\"\"}]"))); for (int i = 0; i < tm.getModules().size(); i++) { if (tm.getModules().get(i) == null) continue; for (int j = 0; j < tm.getModules().get(i).getMacros().size(); j++) { if (tm.getModules().get(i).getMacros().get(j) == null) continue; System.out.println(String.format("c: %s", tm.getModules().get(i).getMacros().get(i).getC())); System.out.println(String.format("l: %s", tm.getModules().get(i).getMacros().get(i).getL())); System.out.println(String.format("m: %s", tm.getModules().get(i).getMacros().get(i).getM())); System.out.println(String.format("t.id: %d", tm.getModules().get(i).getMacros().get(i).getTypeId())); System.out.println(String.format("t.it: %s", tm.getModules().get(i).getMacros().get(i).getLocalizedTypeString())); System.out.println(String.format("w: %s", tm.getModules().get(i).getMacros().get(i).getW())); } } logger.info("Execution terminated"); } ... 

In extreme synthesis, I tried to schematize the problem as follows:

  1. TinyMap class has a modules member, which is an ArrayList of TinyMapModule objects
  2. TinyMapModule class has a macros member, which is an ArrayList of TinyMapMacro objects
  3. TinyMapMacro class maps objects with the only attributes I strictly need.

Now, when I try to deserialize the above JSON string into my objects I get an exception telling me that JSON can't be deserialized:

Exception in thread "main" com.fasterxml.jackson.databind.RuntimeJsonMappingException: Can not deserialize instance of it.asystelsrl.hcsbridge.communication.TinyMapModule out of START_ARRAY token at [Source: java.io.StringReader@3c50507; line: 1, column: 2] at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:122) at it.asystelsrl.hcsbridge.communication.TinyMap.buildTinyMap(TinyMap.java:47) at it.asystelsrl.hcsbridge.tests.TestTinyMap.main(TestTinyMap.java:69) Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of it.asystelsrl.hcsbridge.communication.TinyMapModule out of START_ARRAY token at [Source: java.io.StringReader@3c50507; line: 1, column: 2] at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:599) at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:593) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromArray(BeanDeserializer.java:531) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:141) at com.fasterxml.jackson.databind.MappingIterator.nextValue(MappingIterator.java:188) at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:120) ... 2 more 

I already read a lot about Jackson annotations, custom deserializers, etc. but the only solution I seem to come up with is to convert the TinyMap.modules member from ArrayList<TinyMapModules> to ArrayList<Object> and use a custom deserializer to handle NullType objects.

By this choice (if feasible, because I have not tested it yet) I would lose semantic value of the TinyMap.modules member, and I wouldn't be forced to.

Is there another way I can resolve the null elements issue?

EDIT:

It is important I can preserve ordinal position of non-null objects within this structure, so I should definitely at least replace null elements with something usable as a placeholder.

6
  • 1
    I don't know if this is helpful, but the JSON string you posted is not valid JSON.. Commented Oct 31, 2012 at 15:58
  • @lrsjng : You're right, I'm going to fix it. Commented Oct 31, 2012 at 16:02
  • hm, it's still no valid JSON.. only chance is to change the outer curly brackets into [ and ] to make it an array, since the content has no key values Commented Oct 31, 2012 at 16:06
  • but I guess it's just an example, so the JSON form is not the problem here? Commented Oct 31, 2012 at 16:07
  • @lrsjng Ah, you're obviously right!!! I'm tired as it's been hours I'm beating over this thing. Thanks for your patience. And you're right it is an example, the JSON form is not the problem. Commented Oct 31, 2012 at 16:08

2 Answers 2

2

The problem here is that I made a lot of confusion using Jackson.

I came to understand it reading this article by ProgrammerBruce.

I was trying to deserialize a Collection into something which it is not, as StaxMan suggested in his comment.

Thanks to ProgrammerBruce for his useful and clear article.

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

Comments

1

You're still only showing the theBeans property in your example JSON, instead of the full MyContainer object. And your error sounds like it's actually trying to parse the given JSON as MyContainer.

Just to be sure, can you post the full JSON object, and your deserialization code?

Jackson understands null POJOs just fine.

2 Comments

I'll post everything as soon as I'll get back to the office. In the meanwhile, what I was trying to do is to map the whole JSON array as a MyContainer object. Is it wrong? I tried it for other JSON array structures (without NULL elements in them) and it works very well.
I posted all Java classes, deserialization code and real JSON structure.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.