0

I am trying to parse json file using jackson @JsonProperty. I have an interesting problem at hand. One of the field name that is marked as @JsonProperty can be different based on input source. Example json files below

car1.json --> {"car": {"color": "yellow","type": "luxurySedan"}}
car2.json --> {"car": {"color": "yellow","modeltype": "SUV"}}

My Datamodel is something like

@Data
class Car {

   @JsonProperty("color")
   private String color; 

   @JsonProperty("type")
   private String type; // Don't want to use alias to solve above problem

 }

Second file car2.json does not get parsed. I tried following on field type to get value from a property file (using spring boot) but it is not working as expected. I am reluctant to use alias purely because I will have to change code if field name changes for any one of the file. Can someone help please

@JsonProperty(@Value("${car.type}")) // Compilation error (It's a spring boot project)
@JsonProperty("${car.type}") // Values not read
Prashanth G
  • 31
  • 1
  • 7
  • This is not valid JSON: `{color:"yellow", type:"luxurySedan"}`. Can you check it? For example, [here](https://jsonlint.com/). – andrewJames Mar 10 '20 at 17:30
  • Updated my JSON – Prashanth G Mar 10 '20 at 17:44
  • There is no simple way to implement it if you have unlimited number of possibilities. Probably the simplest approach would be to declare all fields which are constant with `@JsonProperty` annotation and for rest of fields you can use `Map` and `@JsonAnySetter` annotation. Take a look: [How to use dynamic property names for a Json object](https://stackoverflow.com/questions/55684724/how-to-use-dynamic-property-names-for-a-json-object) – Michał Ziober Mar 10 '20 at 19:02

1 Answers1

0

Your JSON doesn't appear to have a car node, so you can't use it as part of your @JsonProperty annotation. Generally speaking you only need to specify the individual node names rather than full paths, as they are evaluated relative to the root node. Where you have nested JSON structures it's conventional to encapsulate those inside a separate class so you still don't need to put full paths in.

class Car {

    @JsonProperty("color")
    private String color;

    @JsonProperty("type")
    private String type;

    @JsonProperty("modeltype")
    private String modelType;

    // The rest of the class
}

Should do the trick for the JSON that you've provided. If a property is missing from the source JSON then its value will simply be null in your Java object.

Your second sample of JSON fails because the Java object that Jackson is trying to unmarshal the JSON into doesn't declare a property named "modeltype", and the default behaviour is to fail on unknown properties. That particular behaviour can be suppressed by adding the following class-level annotation:

@JsonIgnoreProperties(ignoreUnknown = true)

However this will cause Jackson to completely ignore any property for which there is no mapped field, so you will lose any data associated with unknown properties.

JonK
  • 2,097
  • 2
  • 25
  • 36
  • Hi @JonK...Property is not missing instead property name can be dynamic based on the input source. Imagine a case where you get same format of file from 10 different sources but with slight change in property names....this is the scnario I am trying to address. I would not like to have 10 different field names for 10 different source, situation will be worse if every field name is differrent – Prashanth G Mar 10 '20 at 17:47
  • @PrashanthG In that case you might be better off just leaving the Java object as a `Map`. Annotations can't have dynamic values passed into them - their arguments are only processed at compile time. – JonK Mar 10 '20 at 19:55
  • @PrashanthG You could also implement a custom deserializer for your Car class, although personally I wouldn't do that in this particular case, as from a readability/maintainability perspective it would be a little bit too much like *black magic*. Having a Map makes it more evident that you're expecting an unpredictable set of properties. – JonK Mar 10 '20 at 20:04