Skip to content Skip to sidebar Skip to footer

Jackson Generics With Variable Jsonproperty (usage With Generics)

I have class that looks like this: public class Data { @JsonProperty('difficulties') private U[] data; // ... geter setter constructor } And I don't want to

Solution 1:

Based on response of Jackson - Modify an attribute at runtime without annotation by Michał Ziober here I was able to change default field name values by overriding PropertyNamingStrategy:

These are my received JSON examples (simplified):

{"status":"OK","error":null,"data":{"difficulties":[{"value":"easy"},{"value":"medium"}]}}{"status":"ok","error":null,"data":{"countries":[{"code":"AT"},{"code":"BE"}]}}

see the difference in second line where data object contains either difficulties or countries (or many other names based on context).

Response class based on JSON response:

publicclassResponse<T>{
    privateString status;
    privateStringerror;
    private Data<T> data;
    // Getters Setters Constructors
}

Data class based on JSON response:

publicclassData<T> {
    // property name, that will be changed@JsonProperty(DataNamingStrategy.DATA_FIELD)private T[] data;
    // Getters Setters Constructors
}

And this is Naming strategy, that changes default value to runtime specified value

publicclassDataNamingStrategyextendsPropertyNamingStrategy{

    // used by other classes (this will be default field name that should be changed)publicstatic final StringDATA_FIELD = "variable:data";
    privateString fieldName;

    publicDataNamingStrategy(String fieldName) {
        this.fieldName = fieldName;
    }

    // use this to change field name (format "variable":"value") not needed in my case@OverridepublicStringnameForField(MapperConfig<?> config, AnnotatedField field,
            String defaultName) {
        return (defaultName.equals(DATA_FIELD))?
            fieldName :
            super.nameForField(config, field, defaultName);
    }

    // use this to change setter method field name (JSON -> Object with format "variable":{})@OverridepublicStringnameForSetterMethod(MapperConfig<?> config,
            AnnotatedMethod method, String defaultName) {
        return (defaultName.equals(DATA_FIELD))?
            fieldName :
            super.nameForGetterMethod(config, method, defaultName);
    }

    // use this to change getter method field name (Object -> JSON with format "variable":{})// should be same as nameForSetterMethod@OverridepublicStringnameForGetterMethod(MapperConfig<?> config,
            AnnotatedMethod method, String defaultName) {
        returnnameForSetterMethod(config, method, defaultName);
    }
}

And usage should look like this:

ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new DataNamingStrategy(tableName));
JavaType type = mapper.getTypeFactory().constructParametricType(Response.class, dataClass);
Response<U> u = mapper.readValue(result, type);

Where result is Json as String, tableName is String that will be used in JSON instead of default value and dataClass is class for U (for example Difficulty.class).

Better usage of PropertyNamingStrategy should be Map instead of one String. But I just needed to change one particular value.

Also have a look at PropertyNamingStrategy documentation or again at Michał Ziober's answer

Solution 2:

You can use @JsonAnyGetter annotation.

publicclassData<U> {

    @JsonIgnoreprivate U[] data;

    @JsonIgnoreprivateString propertyName;

    publicData(String propertyName) {
        this.propertyName = propertyName;
    }

    // ... geter setter@JsonAnyGetterpublicMap<String, Object> any() {
        returnCollections.singletonMap(propertyName, data);
    }
}

And use it like below:

Data<Difficulties> difficulties = new Data<>("difficulties");

write whatever you want instead of "difficulties" string. Set your list to Data generic class instead of Difficulties object if you want

Post a Comment for "Jackson Generics With Variable Jsonproperty (usage With Generics)"