How to change json field names in bulk - java

I have some json in a hashmap<string, object> and i’m using ObjectMapper to map it json. I need to change the field names of pretty much all of the values.
ex:
change this
{ “field1”:”abc”, “field2”: “xyz”}
to this
{“f1”:”abc”, “f2”:”xyz”}
I’ve read about using Jackson and using annotation #JsonProperty, but in my case it’s just not feasible because i need to change the names of atleast 20+ fields. What’s the best way to do this?

Why can’t you change ur inout source? Such large change is unnecessary and taxing

If you are parsing this Json with ObjectMapper, after getting intermediate DTO you can apply Mixin and export into String and then convert to required DTO.
Convert String to OriginalDTO with field1
Set Jackson mixin to object mapper
ObjectMapper mapper = new ObjectMapper();
#Getter
#Setter
public abstract class FinalMixin {
#JsonProperty("f1")
private String field1;
}
mapper.addMixInAnnotations(OriginalDTO.class, FinalMixin.class);
Convert DTO that you get in step 1 into String
Convert result String into FinalDTO

Related

How to fix invaliddefinitionexception when using ObjectMapper on Pojo that has org.json.JSONObject

I'm not sure if this type of problem was already asked. I couldn't find, so asking
I have a POJO
Class A {
int id;
Object data;
//getter and setters
}
I set org.json.JSONObject type json into data
Option 1:
When I set data to object directly, I get an error from ObjectMapper when doing
objectMapper.writeValueAsString(anInstanceOfA);
Error: InvalidDefinitionException: No serializer found for org.json.JSONObject
{ I assume the problem is between fasterxml and org.json }
Option 2:
If I use toString on JSONObject before setting to an instance of A, I see escape character in the output. The output is unacceptable. Can't sacrifice JSON formatting and structure
Is there a way to leave already JSON structured element as-is, with less conversions?

Change naming of attributes in json without #JsonProperty

I have to convert my json from camelCase to kebab-case.
Example:
My Json:
{
"disclaimerConfirmed" : true
}
And I need:
{
"disclaimer-confirmed" : true
}
I cannot use #JsonProperty because it rename this atributes permanently. I am looking for something which will consume Json (can be as String) and returns modified json(as String).
Jackson supports naming strategies so you could read the input String to map (with camelCase strategy) and then write the map back to a String (with kebab-case which is natively supported );
Specific method you need to switch these conventions in ObjectMapper without annotations is:
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.*);
You can have different serializers for different cases or you can create pojo with #JsonProperty and use those where-ever required.
For example,
class A {
private String disclaimerConfirmed;
}
class AkebabCase {
#JsonProperty("disclaimer-confirmed")
private String disclaimerConfirmed;
}
So, if you want to serialize to kebab-case you can use converters to convert A to AkebabCase and then serialize.

In jackson 2.8, how can I postprocess every deserialized value of class Foo?

I'm building a rest service using jackson with a single instance of ObjectMapper where I can set my configuration. Java-side values are pojos with fields of types like String and int. Very simple, straightforward situation, nothing special.
I want to perform some processing on every field of a given type after deserialization, possibly altering the value that should be put in the pojo field. I don't want to litter my pojos with annotations or anything, it should be self-contained within ObjectMapper. I also don't want to override the existing deserialization code - the data mapping itself should keep working as-is.
Concrete example: say I want to call toUpperCase() on every incoming String because I dislike lower case letters. How can I create this behavior? I was hoping to find something like the following, but it doesn't seem to exist:
objectMapper.getDeserializationConfig().registerValueProcessor(Foo.class, Foo::bar);
I'm familiar with jackson basics like registering a new type (de)serializer, I just don't know anything for this particular type of thing.
Concrete example: say I want to call toUpperCase() on every incoming String because I dislike lower case letters. How can I create this behavior?
Create your custom deserializer for String:
SimpleModule module = new SimpleModule("customDeserializers", Version.unknownVersion());
module.addDeserializer(String.class, new StdDeserializer<String>(String.class) {
#Override
public String deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return jp.getValueAsString().toUpperCase();
}
});
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
The custom deserializer defined above will process only values mapped to String. If a given POJO has a member where its type is UUID, for instance, the value won't be converted to upper case. See the example below:
public class Person {
private UUID id;
private String name;
// Getters and setters
}
String json = "{\"id\": \"6d39b716-ee80-4468-b1e4-b4270d57be99\", \"name\": \"Joe Doe\"}";
Person person = mapper.readValue(json, Person.class);
System.out.println(person.getId()); // Prints 6d39b716-ee80-4468-b1e4-b4270d57be99
System.out.println(person.getName()); // Prints JOE DOE
I guess the best thing to do would be to write my own (de)serializer impl that wraps around an existing (de)serializer, using inheritance or composition, and replaces it in the objectmapper configuration. That way I can call the original conversion logic (through super or a field) and postprocess the result it returns.

how to use #JsonProperty in this case - jackson API with lombok

I know how to use #JsonProperty in jackson API but the below case is different.
I've below json snippet.
{"results":[{"uniqueCount":395}
So, to parse with jackson API the above json, I've written below java pojo class.
package com.jl.models;
import lombok.Data;
#Data
public class Results
{
private int uniqueCount;
}
Later, I got to parse below similar json snippet.
{"results":[{"count":60}
Now, the problem here is I'm unable to parse this json with Results class as it expects a string uniqueCount.
I can easily create another java pojo class having count member variable but I've to create all the parent java classes having instance of Results class.
So, is there any way I can customize Results class having lombok behaviour to parse both the json without impacting each others?
Thanks for your help in advance.
You can use Jackson's #JsonAnySetter annotation to direct all unknown keys to one method and there you can do the assignment yourself:
#Data
public class Results
{
private int uniqueCount;
// all unknown properties will go here
#JsonAnySetter
public void setUnknownProperty(String key, Object value) {
if (key.equals("count")) {
uniqueCount = (Integer)value;
}
}
}

Jackson parse json with unwraping root, but without ability to set #JsonRootName

The rest service responds with
<transaction><trxNumber>1243654</trxNumber><type>INVOICE</type></transaction>
or in JSON:
{"transaction":{"trxNumber":1243654,"type":"INVOICE"}}
There is no problems when I use:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true)
And as resulting class
#JsonRootName("transaction")
public class Transaction {
private String trxNumber;
private String type;
//getters and setters
}
But actually I should use the Transaction class from 3rd party jar, which is exact like above, but has no #JsonRootName("transaction") annotation.
So I end up with
Could not read JSON: Root name 'transaction' does not match expected ('Transaction') for type...
Is there any ways to force Jackson parse to Transaction class without adding any stuff to the Transaction class itself (as I get this file as part of a binary jar)?
I've tried custom PropertyNamingStrategy, but it seems has to do only with field and getter/setter names, but not class names.
Java7, Jackson 2.0.5.
Any suggestions? thanks.
You can do it with mixin feature. You can create simple interface/abstract class like this:
#JsonRootName("transaction")
interface TransactionMixIn {
}
Now, you have to configure ObjectMapper object:
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
mapper.addMixInAnnotations(Transaction.class, TransactionMixIn.class);
And finally you can use it to deserialize JSON:
mapper.readValue(json, Transaction.class);
Second option - you can write custom deserializer for Transaction class.

Categories

Resources