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:
TinyMapclass has a modules member, which is anArrayListofTinyMapModuleobjectsTinyMapModuleclass has a macros member, which is anArrayListofTinyMapMacroobjectsTinyMapMacroclass 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.
[and]to make it an array, since the content has no key values