In my DTO class, there could be fields which might have same #JsonAlias values, but this seems not working with Jackson ObjectMapper.
It seems that ObjectMapper only works for the first occurrence of #JsonAlias and it don't work for the rest #JsonAlias which has same value. I have tried to create an example below for the reference and in that example, Person class has the two fields with name #JsonAlias value.
Code snippet:
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<String, String> values = new HashMap<>();
values.put("name", "TEST NAME");
Person person = new ObjectMapper().convertValue(values, Person.class);
System.out.println("name1: " + person.getName1());
System.out.println("name2: " + person.getName2());
}
static class Person {
#JsonAlias("name")
String name1;
#JsonAlias("name")
String name2;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
}
}
Output:
name1: TEST NAME
name2: null
In the above output. I was expecting the "TEST NAME" for the name2 variable in Person class.
Is there any configuration in Jackson ObjectMapper which will help me to achieve this?
Jackson version - jackson-databind-2.11.4.jar
Solution 1, #JsonGetter #JsonSetter point out to the custom getter\setter
We can use #JsonGetter("name") and #JsonSetter("name") annotations to map one JSON property value to the setter which has handling two properties
public class Person {
#JsonIgnore
private String name1;
#JsonIgnore
private String name2;
#JsonSetter("name")
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
#JsonGetter("name")
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
}
Solution 2, #JsonAlias with the specific setter
We can ignore one field, the second mark with an alias, and add a custom setName setter that maps one JSON value to several fields.
public class Person {
#JsonAlias("name")
private String name1;
#JsonIgnore
private String name2;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name1) {
this.name1 = name1;
}
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
}
Or just add a custom setName setter to your original code
public class Person {
#JsonAlias("name")
String name1;
#JsonAlias("name")
String name2;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name1) {
this.name1 = name1;
}
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
}
Solution 3, #JsonProperty with the specific setter
The same like Solution 2, but instead use #JsonProperty("name")
public class Person {
#JsonProperty("name")
private String name1;
#JsonIgnore
private String name2;
public String getName1() {
return name1;
}
#JsonIgnore
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name1) {
this.name1 = name1;
}
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
}
UPDATE:
In case you do not have the ability to modify DTO object, custom deserializer resolve the problem.
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
public class PersonDeserializer extends StdDeserializer<Person> {
public PersonDeserializer() {
this(null);
}
public PersonDeserializer(Class<?> vc) {
super(vc);
}
#Override
public Person deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
Person person = new Person();
JsonNode node = jp.getCodec().readTree(jp);
String name = node.get("name").asText();
person.setName1(name);
person.setName2(name);
return person;
}
}
Apply deserializer to the DTO object:
#JsonDeserialize(using = PersonDeserializer.class)
public class Person {
private String name1;
private String name2;
//getters and setters
}
OR register custom deserializer on ObjectMapper
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Person.class, new PersonDeserializer());
mapper.registerModule(module);
Related
I cannot properly convert a JSON Object into POJO. I kind of understand where is the problem, but can't figure out, how to deal with it.
Here's all specific data to understand the issue:
JSONObject which I try to deserialize (understanding the values names isn't key to understand the problem):
[{"name":"Rafał","description":"Przykładowy opis profilu","location":"Lublin","interests":[{"0":"Gry komputerowe","1":"Muzyka","2":"Siłownia"}],"age":24,"rowid":2,"username":"lenivius"}]
My POJO class:
public class Users {
private int rowid = 0, age;
private String name, username, e_mail, password, description, location;
private List<String> interests;
public Users() {
}
public Users(int rowid, int age, String name, String username, String e_mail, String password, String description, String location, List<String> interests) {
this.setRowid(rowid);
this.setAge(age);
this.setName(name);
this.setUsername(username);
this.setE_mail(e_mail);
this.setPassword(password);
this.setDescription(description);
this.setLocation(location);
this.setInterests(interests);
}
public int getRowid() {
return rowid;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public String getUsername() {
return username;
}
public String getE_mail() {
return e_mail;
}
public String getPassword() {
return password;
}
public String getDescription() {
return description;
}
public String getLocation() {
return location;
}
public void setRowid(int rowid) {
this.rowid = rowid;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setUsername(String username) {
this.username = username;
}
public void setE_mail(String e_mail) {
this.e_mail = e_mail;
}
public void setPassword(String password) {
this.password = password;
}
public void setDescription(String description) {
this.description = description;
}
public void setLocation(String location) {
this.location = location;
}
public List<String> getInterests() {
return interests;
}
public void setInterests(List<String> interests) {
this.interests = interests;
}
}
And lastly code line which causes the exception to happen:
resultUsers = objectMapper.readValue(responseString, Users[].class);
I can also post full exception message:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (String)"[{"name":"Rafał","description":"Przykładowy opis profilu","location":"Lublin","interests":[{"0":"Gry komputerowe","1":"Muzyka","2":"Siłownia"}],"age":24,"rowid":2,"username":"lenivius"}]"; line: 1, column: 92] (through reference chain: java.lang.Object[][0]->com.example.loveterests.Users["interests"]->java.util.ArrayList[0])
If I understand the problem correctly, then Jackson needs a list of String objects to properly convert JSON into POJO, but inside "interests" key there is a JSON Array, and that's probably where all the is the problem.
Problem is with interests property. In POJO it is represented by List<String> and in JSON Payload by JSON Array[JSON Object] - array with objects, not strings. You can use Map<String, Object> type to handle this:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#AllArgsConstructor
class Users {
private int rowid = 0, age;
private String name, username, e_mail, password, description, location;
private List<Map<String, Object>> interests;
}
I need to create a JSON object structure from set of java pojo classes. This will provide a better understand of how the objects are structured by just looking at the Json file. I tried both Gson and org.codehaus.jackson.map.ObjectMapper libraries. But couldn't generate all the Json tags relevant to all the fields in java pojo objects. The created json file is only having the values from the values stetted objects. I need to have all the fields of pojo objects in the Json file.
Gson
Hotel hotel = new Hotel(); //This hotel object includes multiple objects and those objects also include multiple objects, lists
Gson gson = new GsonBuilder().create();
String json = gson.toJson(hotel);
System.out.println(json);
ObjectMapper
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File("/home/Pojos.json");
This is the class and json response I got.
Hotel.java
package datatypes;
import java.util.ArrayList;
import java.util.List;
public class Hotel {
private String hotelCode;
private String chainCode;
private String hotelName;
private List<Room> rooms = new ArrayList<Room>();
private List<RoomRateRestriction> roomRateRestrictions
= new ArrayList<RoomRateRestriction>();
public String getHotelCode() {
return hotelCode;
}
public void setHotelCode(String hotelCode) {
this.hotelCode = hotelCode;
}
public String getChainCode() {
return chainCode;
}
public void setChainCode(String chainCode) {
this.chainCode = chainCode;
}
public String getHotelName() {
return hotelName;
}
public void setHotelName(String hotelName) {
this.hotelName = hotelName;
}
public List<Room> getRooms() {
return rooms;
}
public void setRooms(List<Room> rooms) {
this.rooms = rooms;
}
public void addRoom(Room room){
this.rooms.add(room);
}
public List<RoomRateRestriction> getRoomRateRestrictions() {
return roomRateRestrictions;
}
public void setRoomRateRestrictions(
List<RoomRateRestriction> roomRateRestrictions) {
this.roomRateRestrictions = roomRateRestrictions;
}
public void addRoomRateRestrictions(
RoomRateRestriction roomRateRestriction) {
this.roomRateRestrictions.add(roomRateRestriction);
}
}
JSON
{
"rooms":[],
"roomRateRestrictions":[]
}
Add serializeNulls() on GsonBuilder() to serialize null fields
Configure Gson to serialize null fields. By default, Gson omits all fields that are null
* during serialization.
class Hotel {
private String name;
private List<Guest> guests = new ArrayList<>(Collections.singleton(new Guest())); //you have to set a value in order to get the structure of the Guest class otherwise it will show an empty list []
//getter setter
}
class Guest {
private String name;
//getter setter
}
Gson
Hotel hotel = new Hotel();
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(hotel);
System.out.println(json);
Output
{
"name":null,
"guests":[
{
"name":null
}
]
}
You can use jackson-databind library.
Maven dependency is :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10</version>
</dependency>
Also please find some of sample example below. Here I used Employee Object which is having nested Address object inside it.
Employee.java
public class Employee {
private int empId;
private String firstName;
private String lastName;
private double salary;
private Address address;
public Employee() {}
public Employee(int empId, String firstName, String lastName, double salary) {
this.empId = empId;
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
}
public Employee(int empId, String firstName, String lastName, double salary, Address address) {
this.empId = empId;
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.address = address;
}
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address.java
public class Address {
private String street;
private String city;
private String state;
private String zip;
private String country;
public Address() {}
public Address(String street, String city, String state, String zip, String country) {
this.street = street;
this.city = city;
this.state = state;
this.zip = zip;
this.country = country;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
I converted a Sample java pojo class to Json and also JSON to pojo object back.
JacksonConvertion.java
public class JacksonConvertion {
public static void main(String[] args) {
pojoToJson();
jsonToPojo();
}
private static void pojoToJson() {
try {
System.out.println("Convert Object to json ");
ObjectMapper mapper = new ObjectMapper();
Address address = new Address("#103, 1st cross, manyta tech park", "Bengaluru", "Karnataka", "560010",
"India");
Address address1 = new Address();
address1.setCity("Bengaluru");
address1.setState("Karnataka");
address1.setCountry("India");
Employee emp = new Employee(1233, "Raju", "BG", 98734.23, address1);
mapper.writeValue(new File("staff.json"), emp);
String jsonString = mapper.writeValueAsString(emp);
System.out.println(jsonString);
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void jsonToPojo() {
try {
System.out.println("Convert Json to Object ");
ObjectMapper mapper = new ObjectMapper();
Employee employee = mapper.readValue(new File("staff.json"), Employee.class);
System.out.println(employee.getFirstName());
System.out.println(employee.getSalary());
System.out.println(employee.getAddress().getCity());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Also included some of links for your reference.
Link1
Link2
I think this would work fine
Add http://www.java2s.com/Code/Jar/c/Downloadcomfasterxmljacksondatabindjar.htm and http://www.java2s.com/Code/Jar/j/Downloadjacksondatabind205sourcesjar.htm to your library.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class javaPojo {
public static void main(String args[]){
Hotel hotel = new Hotel();
ObjectMapper mapper = new ObjectMapper();
try {
String json = mapper.writeValueAsString(hotel);
System.out.println("JSON = " + json);
} catch (JsonProcessingException e) {
e.printStackTrace();
}}
}
Hotel
import java.util.ArrayList;
import java.util.List;
public class Hotel {
private String hotelCode;
private String chainCode;
private String hotelName;
private List<Room> rooms = new ArrayList<Room>();
private List<RoomRateRestriction> roomRateRestrictions
= new ArrayList<RoomRateRestriction>();
public String getHotelCode() {
return hotelCode;
}
public void setHotelCode(String hotelCode) {
this.hotelCode = hotelCode;
}
public String getChainCode() {
return chainCode;
}
public void setChainCode(String chainCode) {
this.chainCode = chainCode;
}
public String getHotelName() {
return hotelName;
}
public void setHotelName(String hotelName) {
this.hotelName = hotelName;
}
public List<Room> getRooms() {
return rooms;
}
public void setRooms(List<Room> rooms) {
this.rooms = rooms;
}
public void addRoom(Room room){
this.rooms.add(room);
}
public List<RoomRateRestriction> getRoomRateRestrictions() {
return roomRateRestrictions;
}
public void setRoomRateRestrictions(
List<RoomRateRestriction> roomRateRestrictions) {
this.roomRateRestrictions = roomRateRestrictions;
}
public void addRoomRateRestrictions(
RoomRateRestriction roomRateRestriction) {
this.roomRateRestrictions.add(roomRateRestriction);
}
}
Room
public class Room {
}
RoomRateRestriction
public class RoomRateRestriction {
}
OUTPUT - JSON = {"hotelCode":null,"chainCode":null,"hotelName":null,"rooms":[],"roomRateRestrictions":[]}
Given the following class:
package com.example.model;
import java.util.Collection;
import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
import org.springframework.data.neo4j.annotation.RelatedToVia;
import org.springframework.security.core.GrantedAuthority;
#NodeEntity
public class User {
private static final String SALT = "cewuiqwzie";
public static final String FRIEND = "FRIEND";
public static final String RATED = "RATED";
#Indexed
String login;
String name;
String password;
String info;
private Roles[] roles;
public User() {
}
public User(String login, String name, String password, Roles... roles) {
this.login = login;
this.name = name;
this.password = encode(password);
this.roles = roles;
}
private String encode(String password) {
return "";
// return new Md5PasswordEncoder().encodePassword(password, SALT);
}
#RelatedToVia(elementClass = Rating.class, type = RATED)
Iterable<Rating> ratings;
#RelatedTo(elementClass = Movie.class, type = RATED)
Set<Movie> favorites;
#RelatedTo(elementClass = User.class, type = FRIEND, direction = Direction.BOTH)
Set<User> friends;
public void addFriend(User friend) {
this.friends.add(friend);
}
public Rating rate(Movie movie, int stars, String comment) {
return relateTo(movie, Rating.class, RATED).rate(stars, comment);
}
public Collection<Rating> getRatings() {
return IteratorUtil.asCollection(ratings);
}
#Override
public String toString() {
return String.format("%s (%s)", name, login);
}
public String getName() {
return name;
}
public Set<User> getFriends() {
return friends;
}
public Roles[] getRole() {
return roles;
}
public String getLogin() {
return login;
}
public String getPassword() {
return password;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public void updatePassword(String old, String newPass1, String newPass2) {
if (!password.equals(encode(old)))
throw new IllegalArgumentException("Existing Password invalid");
if (!newPass1.equals(newPass2))
throw new IllegalArgumentException("New Passwords don't match");
this.password = encode(newPass1);
}
public void setName(String name) {
this.name = name;
}
public boolean isFriend(User other) {
return other != null && getFriends().contains(other);
}
public enum Roles implements GrantedAuthority {
ROLE_USER, ROLE_ADMIN;
#Override
public String getAuthority() {
return name();
}
}
}
I get a compilation exception here:
public Rating rate(Movie movie, int stars, String comment) {
return relateTo(movie, Rating.class, RATED).rate(stars, comment);
}
Following the tutorial here. Any insight as to where this function resides is appreciated.
You're trying to use the advanced mapping mode. See the reference manual for more information. You'll need to set up AspectJ support in your IDE. Methods are woven into your entity classes at compile time.
In the java, commons beanutils, try to set property 'address' and 'creditCardList' to object, but it gave me error :
java.lang.NoSuchMethodException: Property 'address' has no setter method in class 'class com.dao.Student'
but I have this method there. The code is here:
public class Main {
public static void main(String[] args) {
Object student = new Student("John");
Object address = new Address("NJ");
try {
PropertyUtils.setProperty(student, "address", address);
//----------
List list = new ArrayList();
Object creditCard = new CreditCard();
list.add(creditCard);
PropertyUtils.setProperty(student, "creditCardList", list);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Student {
private String name;
private Address address;
private List<CreditCard> creditCardList;
public Student(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public List<CreditCard> getCreditCardList() {
return creditCardList;
}
public void setCreditCardList(List<CreditCard> creditCardList) {
this.creditCardList = creditCardList;
}
}
class Address {
private String name;
public Address(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class CreditCard{
private String cardName;
public String getCardName() {
return cardName;
}
public void setCardName(String cardName) {
this.cardName = cardName;
}
}
Your class Student should be a public class , try making it public and rerun your code.
I moved Student to a own file and made it public, that worked fine :)
I am playing with the Jackson examples and am having some trouble getting deserialization to work with immutable classes and interfaces.
Below is my code:
package com.art.starter.jackson_starter;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
/** * Hello world! * */ public class App {
public static void main( String[] args ) throws JsonGenerationException, JsonMappingException, IOException
{
System.out.println( "Hello World!" );
AddressImpl.AddressBuilder builder = new AddressImpl.AddressBuilder();
NameImpl.Builder nameBuilder = new NameImpl.Builder();
UserImpl.Builder userBuilder = new UserImpl.Builder();
Name name = nameBuilder.first("FirstName")
.last("LastName")
.build();
Address address = builder.setCity("TestCity")
.setCountry("TestCountry")
.setState("PA")
.setStreet("TestAddress")
.setZip(123)
.build();
User user = userBuilder.address(address)
.gender(User.Gender.MALE)
.isVerified(true)
.userImage(new byte[5])
.build();
System.out.println(address);
System.out.println(name);
System.out.println(user);
StringWriter sw = new StringWriter();
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(sw, user);
System.out.println(sw);
StringReader sr = new StringReader("{\"address\":{\"state\":\"PA\",\"country\":\"TestCountry\",\"street\":\"TestAddress\",\"city\":\"TestCity\",\"zip\":123},\"verified\":true,\"gender\":\"MALE\",\"userImage\":\"AAAAAAA=\"}");
/*
This line throws the Exception
*/
User user2 = mapper.readValue(sr, UserImpl.class);
System.out.println(user2);
} }
package com.art.starter.jackson_starter;
import java.util.Arrays;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
public final class UserImpl implements User
{
private final Address address;
private final Gender gender;
private final byte[] userImage;
private final boolean isVerified;
public static class Builder
{
private Address address;
private Gender gender;
// private Name name;
private byte[] userImage;
private boolean isVerified;
public Builder address(Address address)
{
this.address = address;
return this;
}
public Builder gender(Gender gender)
{
this.gender = gender;
return this;
}
// public Builder name(Name name)
// {
// this.name = name;
// return this;
// }
public Builder userImage(byte[] userImage)
{
this.userImage = userImage;
return this;
}
public Builder isVerified(boolean isVerified)
{
this.isVerified = isVerified;
return this;
}
public UserImpl build()
{
return new UserImpl(address, gender, userImage, isVerified);
}
}
#JsonCreator
public UserImpl(#JsonProperty("address") Address address, #JsonProperty("gender") Gender gender, #JsonProperty("userImage") byte[] userImage,
#JsonProperty("verified") boolean isVerified)
{
super();
this.address = address;
this.gender = gender;
this.userImage = userImage;
this.isVerified = isVerified;
}
public Address getAddress()
{
return address;
}
public Gender getGender()
{
return gender;
}
public byte[] getUserImage()
{
return userImage;
}
public boolean isVerified()
{
return isVerified;
}
#Override
public String toString()
{
StringBuilder builder2 = new StringBuilder();
builder2.append("UserImpl [address=");
builder2.append(address);
builder2.append(", gender=");
builder2.append(gender);
builder2.append(", isVerified=");
builder2.append(isVerified);
builder2.append(", name=");
builder2.append(", userImage=");
builder2.append(Arrays.toString(userImage));
builder2.append("]");
return builder2.toString();
}
}
package com.art.starter.jackson_starter;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
public final class AddressImpl implements Address
{
private final String city;
private final String country;
private final String street;
private final String state;
private final int zip;
public static class AddressBuilder
{
private String city;
private String country;
private String street;
private String state;
private int zip;
public AddressBuilder setCity(String city)
{
this.city = city;
return this;
}
public AddressBuilder setCountry(String country)
{
this.country = country;
return this;
}
public AddressBuilder setStreet(String street)
{
this.street = street;
return this;
}
public AddressBuilder setState(String state)
{
this.state = state;
return this;
}
public AddressBuilder setZip(int zip)
{
this.zip = zip;
return this;
}
public AddressImpl build()
{
return new AddressImpl(city, country, street, state, zip);
}
}
#JsonCreator
public AddressImpl(#JsonProperty("city") String city, #JsonProperty("country") String country, #JsonProperty("street") String street,
#JsonProperty("state") String state, #JsonProperty("zip") int zip)
{
this.city = city;
this.country = country;
this.street = street;
this.state = state;
this.zip = zip;
}
public String getCity()
{
return city;
}
public String getCountry()
{
return country;
}
public String getStreet()
{
return street;
}
public String getState()
{
return state;
}
public int getZip()
{
return zip;
}
#Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("AddressImpl [city=");
builder.append(city);
builder.append(", country=");
builder.append(country);
builder.append(", state=");
builder.append(state);
builder.append(", street=");
builder.append(street);
builder.append(", zip=");
builder.append(zip);
builder.append("]");
return builder.toString();
}
}
The issue appears to be with Address. I get this exception:
Exception in thread "main" org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.art.starter.jackson_starter.Address, problem: abstract types can only be instantiated with additional type information
at [Source: java.io.StringReader#785f8172; line: 1, column: 2]
at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
at org.codehaus.jackson.map.deser.StdDeserializationContext.instantiationException(StdDeserializationContext.java:212)
at org.codehaus.jackson.map.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:97)
at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:230)
at org.codehaus.jackson.map.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:595)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:472)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:350)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2391)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1614)
at com.art.starter.jackson_starter.App.main(App.java:56)
I am sure this is because there is no way for Jackson to resolve Address which is an interface to AddressImpl which is a concrete implementation. I have been poking through the docs and have looked at a few articles regarding the #JsonDeserialize(as=AddressImpl.class),but it didn't work. So I am stumped. Has anyone ever gotten this to work, is it even supported?
It works like a champ if I replace Address with AddressImpl in the UserImpl class.
Just in case you hadn't seen it, here's a blog entry that discusses working with immutable objects and Jackson.
But you should definitely be able to use #JsonDeserialize(as=AddressImpl.class); either by adding it to Address.java interface (either directly or by using mix-ins), or by adding it to field or property. One thing to note is that for deserialization, it MUST be next to accessor you use; setter if you have one, if not, next to field. Annotations are not (yet) shared between accessors; so for example adding it to 'getter' would not work.
Jackson 1.8 also finally allows registration of abstract-to-concrete types (see http://jira.codehaus.org/browse/JACKSON-464 for more details) which might be the best option to indicate that 'AddressImpl' is to be used for 'Address'.