I have two JSON strings with the same format from different sources, but one has camelcase, one has snakecase, how can I map them to the same POJO field using Jackson?
For example:
{ "fieldName": "abcd"}
and
{ "field_name": "abcd"}
You should create two setter methods:
class Entity {
private String fieldName;
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public void setField_name(String field_name) {
this.fieldName = field_name;
}
}
You can use the #JsonCreator annotation to specify how to construct your object.
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyPojo {
private final String fieldName;
// Jackson version
#JsonCreator
public static MyPojo of(
#JsonProperty("field_name") final String fieldName1,
#JsonProperty("fieldName") final String fieldName2) {
final String name = fieldName1 != null ? fieldName1 : fieldName2;
return of(name);
}
// Programmatic version that you can use from code
public static MyPojo of(
#JsonProperty("fieldName") final String fieldName) {
return new MyPojo(fieldName);
}
private MyPojo(final String fieldName) {
this.fieldName = fieldName;
}
public String fieldName() {
return fieldName;
}
}
Your POJO will be neat and clean (without duplicate fields) and the creation-code is separated nicely.
Related
I have a class that has some additional getters for derived values. When I serialize this with jackson objectmapper, it writes out that field as well. Is there a way to avoid that?
example -
public class CustomPath implements Serializable {
private String path;
private String name;
private String extension = ".txt";
#JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public CustomPath(#JsonProperty("path") String path, #JsonProperty("name") String name) {
this.path = path;
this.name = name;
}
public String getPath()
{ return this.path;}
public void setPath(String path)
{ this.path = path;}
public String getName()
{ return this.name;}
public void setName(String name)
{ this.name = name;}
public String getExtension()
{ return this.extension;}
public void setExtension(String extension)
{ this.extension = extension;}
public String getFullPath() //do not want to serialize this
{ return this.path +"/" + this.name + this.extension;}
}
The json for a class like this looks like -
{
path: somepath
name: somename
extension: .txt
fullPath: somepath/somename.txt
}
But I do not want to serialize 'fullPath' in the example above. Is there any way I can avoid that?
You need to annotate the getFullPath() method with #JsonIgnore:
#JsonIgnore
public String getFullPath() // do not want to serialize this
{
return this.path + "/" + this.name + this.extension;
}
Then the JSON output will look like this:
{
"path" : "somePath",
"name" : "someName",
"extension" : ".txt"
}
Im using #JsonAnySetter and #JsonAnyGetter in my POJO class using my Custom serialization with DSL JSON class, the Map is initialized but the other properties are always null.
My POJO class:
#CompiledJson
public class Name {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Map<String,String> properties = new HashMap<String,String>();
public Name() {
// TODO Auto-generated constructor stub
}
#JsonAnyGetter
public Map<String, String> get() {
return this.properties;
}
#JsonAnySetter
public void set(String key, String value) {
this.properties.put(key, value);
}
De/Serializing using DSLJson serialize() and deserialize() methods. I do not see any error also, but properties remains null in JSON. I doubt if Jackson annotations are supported by DSL Json. :/
Spring Boot App with DSL Json and Jackson Annotations
UPDATE
I want to parse MyClass, which is a part of RootClass:
#Compiledjson
public class RootClass {
private String id;
private List<MyClass> myclass;
private AnotherCLass class2;
//getters and setter here
}
#CompiledJson
public class MyClass implements JsonObject {
private String name;
private Map<String, String> properties; //want this to behave like Jackson's #JsonAnySetter/Getter annotation.
//The implementation of MapConverter serializer you mentioned below.
}
The entire code parses through custom Message reader and writer.
While sending my JSON Body, It'll be like this :
{
"id" : "1234",
"myclass" :
[
{
"name" : "abcd",
//any dynamic properties I want to add will go here
"test" : "test1",
"anything" : "anything"
}
],
"class2" : "test5"
}
Thank you :)
DSL-JSON doesn't support such get()/set(string, string) method pairs.
It does understand Map<String, String> so if you expose properties it will work on that. But not in this kind of setup.
As of v1.1 you have two options for solving such problems, both of them are covered in example project
If you wish to reuse existing converters, your solution can look like this:
public static class MyClass {
private String name;
private Map<String, String> properties;
#JsonConverter(target = MyClass.class)
public static class MyClassConverter {
public static final JsonReader.ReadObject<MyClass> JSON_READER = new JsonReader.ReadObject<MyClass>() {
public MyClass read(JsonReader reader) throws IOException {
Map<String, String> properties = MapConverter.deserialize(reader);
MyClass result = new MyClass();
result.name = properties.get("name");
result.properties = properties;
return result;
}
};
public static final JsonWriter.WriteObject<MyClass> JSON_WRITER = new JsonWriter.WriteObject<MyClass>() {
public void write(JsonWriter writer, MyClass value) {
MapConverter.serialize(value.properties, writer);
}
};
}
}
I have a class with lots of attributes which are required for server side logic, but a few of those are required for UI. Now when I am creating a json from the class, all the attributes are written to json. I want to ignore some values only when it is converted to json. I Tried with #JsonIgnore. But it is not working.
My Class Is
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonIgnoreProperties(ignoreUnknown = true)
public class Student {
#JsonProperty("id")
protected Integer id;
#JsonProperty("name")
protected String name;
/**
* This field I want to ignore in json.
* Thus used #JsonIgnore in its getter
*/
#JsonProperty("securityCode")
protected String securityCode;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#JsonIgnore
public String getSecurityCode() {
return securityCode;
}
public void setSecurityCode(String securityCode) {
this.securityCode = securityCode;
}
}
And I am writing this using
public static StringBuilder convertToJson(Object value){
StringBuilder stringValue = new StringBuilder();
ObjectMapper mapper = new ObjectMapper();
try {
stringValue.append(mapper.writeValueAsString(value));
} catch (JsonProcessingException e) {
logger.error("Error while converting to json>>",e);
}
return stringValue;
}
My Expected json should contain only :
id:1
name:abc
but what I am getting is
id:1
name:abc
securityCode:_gshb_90880..some_value.
What is wrong here, please help
Your #JsonProperty annotation overrides #JsonIgnore annotation. Remove #JsonProperty from securityCode and your desired json output will be produced.
If you want more advanced ignoring / filtering please take a look at:
#JsonView : http://wiki.fasterxml.com/JacksonJsonViews
#JsonFilter : http://wiki.fasterxml.com/JacksonFeatureJsonFilter
My POJO is :
import org.jongo.marshall.jackson.id.Id;
public class User {
#Id
private String id;
private String name;
private int age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
I get user from mongo database and want to output him into a file with jackson mapper
ObjectMapper mapper = new ObjectMapper();
mapper.writerWithDefaultPrettyPrinter().writeValue(new File("c:/user.txt"), user);
and I get something like this in my file
{
"name" : "John",
"age" : 23,
"_id" : {
"time" : 1358443593000,
"inc" : 660831772,
"machine" : 2028353122,
"new" : false,
"timeSecond" : 1358443593
}
}
I need id field to be stored into a file as string because when i deserialize this object my id field in pojo looks something like this
{
"time":1358443593000,
"inc":660831772,
"machine":2028353122,
"new":false,
"timeSecond":1358443593
}
Any help will be apreciated
Answering my own question. Found solution here Spring 3.2 and Jackson 2: add custom object mapper
I needed custom object mapper and ObjectId serializer.
public class ObjectIdSerializer extends JsonSerializer<ObjectId> {
#Override
public void serialize(ObjectId value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeString(value.toString());
}
}
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
SimpleModule module = new SimpleModule("ObjectIdmodule");
module.addSerializer(ObjectId.class, new ObjectIdSerializer());
this.registerModule(module);
}
}
I found an easy attempt using springboot 2.5.4.
Just by adding a Jackson2ObjectMapperBuilderCustomizer bean will do the trick.
#Configuration
public class JacksonMapperConfiguration
{
#Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return builder -> builder.serializerByType(ObjectId.class, new ToStringSerializer());
}
}
Here is a simple solution for serialization if you don't have a model for the object being stored:
client.getDatabase("db").getCollection("collection").find().onEach { it["_id"] = it["_id"].toString() }
"onEach" is a kotlin function. If you use Java, then change it to a simple foreach.
It's not efficient to iterate over the entire list just for the id. Only use it for small lists where performance is less important than short code.
So my entities look like this:
public class HappyClass<T>
{
private String id;
prviate int ver;
private Object obj;
public String getId()
{
return this.id;
}
public void setId( String id )
{
this.id = id;
}
public int getVer()
{
return this.ver;
}
public void setVer( int ver )
{
this.ver = ver;
}
#JsonTypeInfo( use = Id.NONE )
public T getObj()
{
return obj;
}
public void setObj( T obj )
{
this.obj = obj;
}
}
public class HappyGeneric
{
private String someStuff();
public String getSomeStuff()
{
return this.someStuff();
}
public void setSomeStuff( String someStuff )
{
this.someStuff = someStuff;
}
}
If I instantiate a class like this:
HappyClass<HappyGeneric> hc = new HappyClass<HappyGeneric>();
If I send it to Spring in a #ResponseBody it returns this:
{
"id" : "iamsomeid",
"ver" : 123,
"obj" : {
"someStuff" : "iamsomestuff"
}
}
However, when Spring and/or Jackson attempts to unmarshal the same JSON, it figures out that the main class is a HappyClass, however, the getObj() it unmarshals to a LinkedHashMap and not a HappyGeneric no matter what I seem to annotate it with.
Anybody have any ideas how I can force Jackson to unmarshal that generic to the original class?
Thanks!
EDIT: I'm aware I can call mapper.convertValue( blah.getObj(), HappyGeneric.class ) and get the object out that way-- I was hoping to get Spring to figure it out automatically (through annotations, for example).