jackson custom deserializer not called - java

I have the following endpoint in retrofit:
#GET("user/detail")
Observable<JacksonResponse<User>> getUserDetail();
This endpoint returns the following result:
{
"code":1012,
"status":"sucess",
"message":"Datos Del Usuario",
"time":"28-10-2015 10:42:04",
"data":{
"id_hash":977417640,
"user_name":"Daniel",
"user_surname":"Hdz Iglesias",
"birthdate":"1990-02-07",
"height":190,
"weight":80,
"sex":2,
"photo_path":" https:\/\/graph.facebook.com
\/422\/picture?width=100&height=100"
}
}
Here is the definition of the class:
public class JacksonResponse<T> {
private Integer code;
private String status;
private String message;
private String time;
#JsonInclude(JsonInclude.Include.NON_NULL)
private T data;
public JacksonResponse(){}
#JsonCreator
public JacksonResponse(
#JsonProperty("code") Integer code,
#JsonProperty("status") String status,
#JsonProperty("message") String message,
#JsonProperty("time") String time,
#JsonProperty("data") T data) {
this.code = code;
this.status = status;
this.message = message;
this.time = time;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
I want the content "data" is mapped to the user class, whose extract show here:
#JsonIgnoreProperties(ignoreUnknown = true)
#ModelContainer
#Table(database = AppDatabase.class)
public class User extends BaseModel {
#PrimaryKey(autoincrement = true)
private Long id;
#Column
private Long idFacebook;
#Column
#JsonProperty("user_name")
private String name;
#Column
#JsonProperty("user_surname")
private String surname;
#Column
private Date birthday;
#Column
#JsonProperty("height")
private Double height;
#Column
#JsonProperty("weight")
private Double weight;
#Column
private String tokenFacebook;
#Column
#JsonProperty("sex")
private Integer sex;
#Column
private String email;
#Column
private String token;
#Column
private Date lastActivity;
#Column
#JsonProperty("id_hash")
private Long idHash;
#Column
#JsonProperty("photo_path")
private String photoPath;
To birthdate, I have defined a custom deserializer, whose code show here:
public class BirthdayDeserializer extends JsonDeserializer<Date> {
#Override
public Date deserialize(JsonParser jsonparser, DeserializationContext deserializationcontext) throws IOException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = jsonparser.getText();
try {
return format.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
I am using this as follows (at User class):
#JsonProperty("birthday")
#JsonDeserialize(using = BirthdayDeserializer.class)
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
but this is never called.
Any idea what 's going on?

You Pojo and JSON does not map. You need to have a Data.java which should have properties as given in the JSON. you classes should be as below based on the json given above.
User.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonIgnoreProperties(ignoreUnknown = true)
public class User {
#JsonProperty("code")
public Integer code;
#JsonProperty("status")
public String status;
#JsonProperty("message")
public String message;
#JsonProperty("time")
public String time;
#JsonProperty("data")
public Data data;
}
Data.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
#JsonIgnoreProperties(ignoreUnknown = true)
public class Data {
#JsonProperty("id_hash")
public Integer idHash;
#JsonProperty("user_name")
public String userName;
#JsonProperty("user_surname")
public String userSurname;
#JsonProperty("birthdate")
#JsonDeserialize(using = BirthdayDeserializer.class)
public Date birthdate;
#JsonProperty("height")
public Integer height;
#JsonProperty("weight")
public Integer weight;
#JsonProperty("sex")
public Integer sex;
#JsonProperty("photo_path")
public String photoPath;
}
Main.java to test it.
public class Main {
public static void main(String[] args) throws IOException {
String json = "{\n" +
" \"code\": 1012,\n" +
" \"status\": \"sucess\",\n" +
" \"message\": \"Datos Del Usuario\",\n" +
" \"time\": \"28-10-2015 10:42:04\",\n" +
" \"data\": {\n" +
" \"id_hash\": 977417640,\n" +
" \"user_name\": \"Daniel\",\n" +
" \"user_surname\": \"Hdz Iglesias\",\n" +
" \"birthdate\": \"1990-02-07\",\n" +
" \"height\": 190,\n" +
" \"weight\": 80,\n" +
" \"sex\": 2\n" +
" }\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Date.class, new BirthdayDeserializer());
mapper.registerModule(module);
User readValue = mapper.readValue(json, User.class);
}
}

Related

JSON parse error, unable to deserialize value of type `java.time.LocalDate` in STS 4.15.3 windows version

I'm new to this tool and I'm having trouble with this specific issue. I looked for an example But could not find something similar, better, I found a possible solution, but in my case It doesn't work.
I have this narrow project that resembles our famous CRUD, and I'm trying to reference the primary key from one table to another.
Client Entity:
#Entity
#Table(name = "client")
public class Client {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "cpf", length = 14)
private String cpf;
#Column(name = "name", length = 100)
private String name;
#Column(name = "birth_date")
private LocalDate birthDate;
#Column(name = "address", length = 255)
private String address;
#Column(name = "telephone", length = 14)
private String telephone;
#Column(name = "email", length = 200)
private String email;
#Column(name = "date_register", insertable = true, updatable = false)
private LocalDate dateRegister;
public Client() {
super();
}
public Client(Long id, String cpf, String name, LocalDate birthDate, String address, String telephone, String email, LocalDate dateRegister) {
super();
this.id = id;
this.cpf = cpf;
this.name = name;
this.birthDate = birthDate;
this.address = address;
this.telephone = telephone;
this.email = email;
this.dateRegister = dateRegister;
}
public Client(String cpf, String name, LocalDate birthDate, String address, String telephone, String email, LocalDate dateRegister) {
super();
this.cpf = cpf;
this.name = name;
this.birthDate = birthDate;
this.address = address;
this.telephone = telephone;
this.email = email;
this.dateRegister = dateRegister;
}
#PrePersist
public void prePersist() {
setDateRegister(LocalDate.now());
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCpf() {
return cpf;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDate getBirthDate() {
return birthDate;
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public LocalDate getDateRegister() {
return dateRegister;
}
public void setDateRegister(LocalDate dateRegister) {
this.dateRegister = dateRegister;
}
#Override
public String toString() {
return "Client [id=" + id + ", cpf=" + cpf + ", name=" + name + ", birthDate=" + birthDate + ", address="
+ address + ", telephone=" + telephone + ", email=" + email + ", dateRegister=" + dateRegister + "]";
}
}
Sale Entity:
#Entity
#Table(name = "sale")
public class Sale {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "client_id")
private Client client;
#OneToMany(mappedBy = "sale")
private List<SaleItem> items;
#Column(name = "payment_type", length = 10)
#Enumerated(EnumType.STRING)
private PaymentType paymentType;
#Column(name = "amount")
private BigDecimal amount;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public List<SaleItem> getItems() {
return items;
}
public void setItems(List<SaleItem> items) {
this.items = items;
}
public PaymentType getPaymentType() {
return paymentType;
}
public void setPaymentType(PaymentType paymentType) {
this.paymentType = paymentType;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
#Override
public String toString() {
return "Sale [id=" + id + ", client=" + client + ", items=" + items + ", paymentType=" + paymentType
+ ", amount=" + amount + "]";
}
}
The objective is to link the client to a sale through its primary key. These two codes refer to the sales repository and its controller:
SaleRepository:
public interface SaleRepository extends JpaRepository<Sale, Long> {
}
SaleController:
#RestController
#RequestMapping("/api/sales")
#CrossOrigin("*")
public class SaleController {
#Autowired
private SaleRepository repository;
#Autowired
private SaleItemRepository saleItemrepository;
#PostMapping
#Transactional
public void save(#RequestBody Sale sale) {
repository.save(sale);
sale.getItems().stream().forEach(saleItem -> saleItem.setSale(sale));
saleItemrepository.saveAll(sale.getItems());
}
}
And the problem is exactly how this reference is being made. In the current private Client client; way , the client object is being passed in full instead of its id, that's why it throws this following error when I try to register the sale.
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.time.LocalDate` from String "31/05/1968": Failed to deserialize java.time.LocalDate: (java.time.format.DateTimeParseException) Text '31/05/1968' could not be parsed at index 0; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.LocalDate` from String "31/05/1968": Failed to deserialize java.time.LocalDate: (java.time.format.DateTimeParseException) Text '31/05/1968' could not be parsed at index 0<EOL> at [Source: (PushbackInputStream); line: 1, column: 87] (through reference chain: MyNameIsRafaelSampaio.github.com.bruxo_vendas_ltda_api.model.Sale["client"]->MyNameIsRafaelSampaio.github.com.bruxo_vendas_ltda_api.model.Client["birthDate"])]
As was to be expected, since the column birthDate present in the client entity is not being treated correctly in the sale entity. I did research on a possible solution but none made much sense to me, I believe for being a newbie, one of the solutions that I found more understandable was the use of the #MapsId tag. I tried to make changes to adapt, but I was not successful, if you can help I will be grateful.

Deserialise object into a subtype dynamically using gson

I have a base class
public class Box<T> {
private T entity;
public T getEntity() {
return entity;
}
void setEntity(T entity) {
this.entity = entity;
}
}
It has 2 implementations.
// Class Person
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// Class Machine
public class Machine {
private String macAddress;
private String type;
public Machine(String macAddress, String type) {
this.macAddress = macAddress;
this.type = type;
}
}
If I want to serialise either of classA or class B objects, I will do it like this
Type typeTokenPerson = new TypeToken< Box <Person>>() {}.getType();
String userJson = gson.toJson(boxWithPersonObject, typeTokenPerson);
But the problem here is I need to know the type at compile time. I have a use case where I don't know this at compile-time, in other words, I have a json which I want to deserialize into either Person or Animal and I want to do this at runtime based on some condition.
Is there a way to do this usig Gson ?
Example:
Lets say we have a json like this
{
"entity": {
"name": "ABC",
"age": 10
}
}
This is of type Person. I want to deserialise this into an object of type Box<Person>
Gson can do it like this.
package com.example.demo;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Type;
import java.time.Duration;
import java.time.LocalDateTime;
public class GsonDemo {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private <T> Box<T> parseResponse(String responseData) {
Gson gson = new Gson();
Type jsonType = new TypeToken<Box<T>>() {
}.getType();
Box<T> result = gson.fromJson(responseData, jsonType);
return result;
}
#Test
public void test() {
LocalDateTime start = LocalDateTime.now();
try {
String json = "{ \"entity\": { \"name\": \"ABC\", \"age\": 10 }}";
Box<Person> objectBox = parseResponse(json);
System.out.println(objectBox);
String json2 = "{\n \"entity\": { \"macAddress\": \"DEF\", \"type\": \"def\" }}";
Box<Machine> objectBox2 = parseResponse(json2);
System.out.println(objectBox2);
} catch (Exception e) {
logger.error("Error", e);
}
LocalDateTime end = LocalDateTime.now();
logger.info("Cost time {}", Duration.between(start, end).toMillis() + "ms");
}
public class Box<T> {
private T entity;
public T getEntity() {
return entity;
}
void setEntity(T entity) {
this.entity = entity;
}
#Override
public String toString() {
return "Box{" + "entity=" + entity + '}';
}
}
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
public class Machine {
private String macAddress;
private String type;
public Machine(String macAddress, String type) {
this.macAddress = macAddress;
this.type = type;
}
public String getMacAddress() {
return macAddress;
}
public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public String toString() {
return "Machine{" + "macAddress='" + macAddress + '\'' + ", type='" + type + '\'' + '}';
}
}
}

Is it okay to add an enum to a Jackson annotated class?

I have added an enum to a Class and the class is annotated with Jackson annotations. I don't want this enum to be considered during serialization or deserialization. Do I need to add any special tags to ignore the enum, like we do #JsonIgnore for methods or variables ?
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "name", "license", "description" })
public class Car {
#JsonProperty("name")
private String name;
#JsonProperty("license")
private String license;
#JsonProperty("description")
private String description;
#JsonProperty("name")
public String getName() {
return name;
}
#JsonProperty("name")
public void setName(String name) {
this.name = name;
}
#JsonProperty("license")
public String getLicense() {
return license;
}
#JsonProperty("license")
public void setLicense(String license) {
this.license = license;
}
#JsonProperty("description")
public String getDescription() {
return description;
}
#JsonProperty("description")
public void setDescription(String description) {
this.description = description;
}
#JsonIgnore
public Type getType() {
if(this.description.contains("electric")) {
return Type.ELECTRIC;
}else if(this.description.contains("diesel")) {
return Type.DIESEL;
}else {
return Type.UNKNOWN;
}
}
public enum Type {
ELECTRIC, DIESEL, GASOLINE, HYDROGEN, BIOFUEL, UNKNOWN
}
}
Here is some code to use this class. It works fine.
public class EnumJsonTester {
public static void main(String [] args) throws Exception {
String json = "{\r\n" +
" \"name\": \"Tesla Model S\",\r\n" +
" \"license\": \"1234\",\r\n" +
" \"description\": \"electric powered vehicle.\"\r\n" +
"}";
Car tesla = Utils.jsonToObject(json, Car.class);
System.out.println("My Car: " + tesla.getType());
}
}

How to pull specific object from Json String

I am new to Json Parsing issue I have the below Json object and I need to get the User object from the below Json
{
"aud": "RoomyClinetApps",
"sub": "AAAA",
"User": {
"firtsName": "Godavarthi",
"LastName": "chaitanya"
},
"iss": "Roomy",
"iat": 1499279510
}
The below is the code I am trying to pull the User object where the the above json is in jsonInString variable when i trying t print I am getting null
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
User user= mapper.readValue(jsonInString.toString(), User.class);
System.out.println(user.getFirtsName()); --> Null
public class User {
#JsonProperty
private String firtsName;
#JsonProperty
private String LastName;
}
Could some one please Provide me a working code which is more appreciable.
Thanks
Chaitanya
Tested the below code. It worked for me. Try this once.
public class Test {
public static void main(String[] args) throws IOException {
String jsonInString = "{\n"
+ " \"aud\": \"RoomyClinetApps\",\n"
+ " \"sub\": \"AAAA\",\n"
+ " \"user\": {\n"
+ " \"firtsName\": \"Godavarthi\",\n"
+ " \"LastName\": \"chaitanya\"\n"
+ " },\n"
+ " \"iss\": \"Roomy\",\n"
+ " \"iat\": 1499279510\n"
+ "}";
ObjectMapper mapper = new ObjectMapper().configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonObject jobj = mapper.readValue(jsonInString.toString(), JsonObject.class);
System.out.println(jobj.getUser().getFirtsName());
}
}
class User {
private String firtsName;
private String LastName;
public String getFirtsName() {
return firtsName;
}
public void setFirtsName(String firtsName) {
this.firtsName = firtsName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String LastName) {
this.LastName = LastName;
}
}
class JsonObject {
private String aud;
private String sub;
private User user;
private String iss;
private long iat;
public String getAud() {
return aud;
}
public void setAud(String aud) {
this.aud = aud;
}
public String getSub() {
return sub;
}
public void setSub(String sub) {
this.sub = sub;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getIss() {
return iss;
}
public void setIss(String iss) {
this.iss = iss;
}
public long getIat() {
return iat;
}
public void setIat(long iat) {
this.iat = iat;
}
}
Hope this is helpful.
public class User {
#JsonProperty
private String firtsName;
#JsonProperty
private String LastName;
}
public class JsonObject{
public string aud;
public String sub;
public User user;
public String iss;
public long iat;
}
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonObject user= mapper.readValue(jsonInString.toString(), JsonObject.class);

How to convert Json to Java Object, Deserializing Json

data_user = "{"id":1,"lastName":"lastName","name":"name","school":{"id":1}}"
public class School {
private int id;
private String name;
}
public class User {
private int id;
private String lastName;
private String name;
private School school;
}
How to deserialize Json data_user to java object User?
I tried with Gson :
Gson gson = new Gson();
User user = gson.fromJson(data_user, User.class)
But I have an error with this code because the Json contains a school which hasn't the school's name.
How Can I serialize the Json to java Object?
School.java
public class School {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "School [id=" + id + ", name=" + name + "]";
}
}
User.java
public class User {
private int id;
private String lastName;
private String name;
private School school;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
#Override
public String toString() {
return "User [id=" + id + ", lastName=" + lastName + ", name=" + name
+ ", school=" + school + "]";
}
}
Main.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.testgson.beans.User;
public class Main {
private static Gson gson;
static {
gson = new GsonBuilder().create();
}
public static void main(String[] args) {
String j = "{\"id\":1,\"lastName\":\"lastName\",\"name\":\"ignacio\",\"school\":{\"id\":1}}";
User u = gson.fromJson(j, User.class);
System.out.println(u);
}
}
Result
User [id=1, lastName=lastName, name=ignacio, school=School [id=1, name=null]]
Try with the Jackson Library. With Gson with should have not any problem, I tried with the code of #Saurabh and it work well

Categories

Resources