How to implement customized serialization feature in fasterxml - java

My JSON:
{
"name": "asdf",
"age": "15",
"address": {
"street": "asdf"
}
}
If street is null, with JsonSerialize.Inclusion.NON_NULL, I can get..
{
"name": "asdf",
"age": "15",
"address": {}
}
But I want to get something like this.. (when address is not null, it is a new/empty object. But street is null.)
{
"name": "asdf",
"age": "15"
}
I thought to have custom serialization feature like JsonSerialize.Inclusion.VALID_OBJECT.
Adding isValid() method in the Address class then if that returns true serialize else don't serialize.
But I don't know how to proceed further/which class to override. Is this possible or any other views on this? Please suggest.
Added classes
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
Customer customer = new Customer();
customer.setName("name");
customer.setAddress(new Address());
mapper.writeValue(new File("d:\\customer.json"), customer);
}
#JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class Customer {
private String name;
private Address address;
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;
}
}
#JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class Address {
private String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
Note: I am not worrying about deserialization now. i.e, loss of address object.
Thanks in advance.

Customized JSON Object using Serialization is Very Simple.
I have wrote a claas in my project i am giving u a clue that how to Implement this in Projects
Loan Application (POJO Class)
import java.io.Serializable;
import java.util.List;
import org.webservice.business.serializer.LoanApplicationSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
#JsonSerialize(using=LoanApplicationSerializer.class)
public class LoanApplication implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private double amount;
private User borrowerId;
private String businessType;
private String currency;
private int duration;
private Date lastChangeDate;
private long loanApplicationId;
private String myStory;
private String productCategory;
private String purpose;
private Date startDate;
private String status;
private String type;
private String salesRepresentative;
Now LoanApplicationSerializer class that contains the Customization using Serialization Logic................
package org.ovamba.business.serializer;
import java.io.IOException;
import org.webservice.business.dto.LoanApplication;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class LoanApplicationSerializer extends JsonSerializer<LoanApplication> {
#Override
public void serialize(LoanApplication prm_objObjectToSerialize, JsonGenerator prm_objJsonGenerator, SerializerProvider prm_objSerializerProvider) throws IOException, JsonProcessingException {
if (null == prm_objObjectToSerialize) {
} else {
try {
prm_objJsonGenerator.writeStartObject();
prm_objJsonGenerator.writeNumberField("applicationId", prm_objObjectToSerialize.getLoanApplicationId());
prm_objJsonGenerator.writeStringField("status", prm_objObjectToSerialize.getStatus());
prm_objJsonGenerator.writeNumberField("amount", prm_objObjectToSerialize.getAmount());
prm_objJsonGenerator.writeNumberField("startdate", prm_objObjectToSerialize.getStartDate().getTime());
prm_objJsonGenerator.writeNumberField("duration", prm_objObjectToSerialize.getDuration());
prm_objJsonGenerator.writeStringField("businesstype", prm_objObjectToSerialize.getBusinessType());
prm_objJsonGenerator.writeStringField("currency", prm_objObjectToSerialize.getCurrency());
prm_objJsonGenerator.writeStringField("productcategory", prm_objObjectToSerialize.getProductCategory());
prm_objJsonGenerator.writeStringField("purpose", prm_objObjectToSerialize.getPurpose());
prm_objJsonGenerator.writeStringField("mystory", prm_objObjectToSerialize.getMyStory());
prm_objJsonGenerator.writeStringField("salesRepresentative", prm_objObjectToSerialize.getSalesRepresentative());
} catch (Exception v_exException) {
//ExceptionController.getInstance().error("Error while Serializing the Loan Application Object", v_exException);
} finally {
prm_objJsonGenerator.writeEndObject();
}
}
}
}
Hope This may help u alot. Thanks..

You can do it by annotating your class with #JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
Example:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public myClass{
// attributes and accessors
}
You can find some useful informations at Jackson faster xml

Related

Parsing JSON and Converting in List Of Object

I have a json response received from API Call the sample response is something like this
{
"meta": {
"code": "200"
},
"data": [
{
"Id": 44,
"Name": "Malgudi ABC"
},
{
"Id": 45,
"Name": "Malgudi, DEF"
}
]
}
I am trying to make List of Object from it, the code that i've written for this is
private static List<TPDetails> getListOfTpDetails(ResponseEntity<?> responseEntity){
ObjectMapper objectMapper = new ObjectMapper();
List<TPDetails> tpDetailsList = objectMapper.convertValue(responseEntity.getBody().getClass(), new TypeReference<TPDetails>(){});
return tpDetailsList;
}
Where TPDetails Object is Like this
public class TPDetails {
int Id;
String Name;
}
the code which i have used is resulting in
java.lang.IllegalArgumentException: Unrecognized field "meta" (class com.sbo.abc.model.TPDetails), not marked as ignorable (2 known properties: "Id", "Name"])
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.sbo.abc.model.TPDetails["meta"])
I want to convert the Above JSON response in List
List<TPDetails> abc = [
{"Id": 44, "Name": "Malgudi ABC"},
{"Id": 45,"Name": "Malgudi DEF"}
]
Any help would be highly appreciable.Thanks well in advance
Create 2 more classes like
public class Temp {
Meta meta;
List<TPDetails> data;
}
public class Meta {
String code;
}
and now convert this json to Temp class.
Temp temp = objectMapper.convertValue(responseEntity.getBody().getClass(), new TypeReference<Temp>(){});
UPDATED :
Make sure responseEntity.getBody() return the exact Json String which you mentioned above.
Temp temp = objectMapper.readValue(responseEntity.getBody(), new TypeReference<Temp>(){});
The format of your java class does not reflect the json you are parsing. I think it should be:
class Response {
Meta meta;
List<TPDetails> data;
}
class Meta {
String code;
}
You should then pass Response to your TypeReference: new TypeReference<Response>(){}
If you don't care about the meta field, you can add #JsonIgnoreProperties
to your response class and get rid of the Meta class and field.
Create/update following class, I am storing JSON file, since do not have service, but should be fine and Able to parse it and read it from the following model.
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.List;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"meta",
"data"
})
public class OuterPoJo {
#JsonProperty("meta")
private Meta meta;
#JsonProperty("data")
private List<TPDetails> data = null;
#JsonProperty("meta")
public Meta getMeta() {
return meta;
}
#JsonProperty("meta")
public void setMeta(Meta meta) {
this.meta = meta;
}
#JsonProperty("data")
public List<TPDetails> getData() {
return data;
}
#JsonProperty("data")
public void setData(List<TPDetails> data) {
this.data = data;
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"code"
})
public class Meta {
#JsonProperty("code")
private String code;
#JsonProperty("code")
public String getCode() {
return code;
}
#JsonProperty("code")
public void setCode(String code) {
this.code = code;
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"Id",
"Name"
})
public class TPDetails {
#JsonProperty("Id")
private Integer id;
#JsonProperty("Name")
private String name;
#JsonProperty("Id")
public Integer getId() {
return id;
}
#JsonProperty("Id")
public void setId(Integer id) {
this.id = id;
}
#JsonProperty("Name")
public String getName() {
return name;
}
#JsonProperty("Name")
public void setName(String name) {
this.name = name;
}
}
import java.io.File;
public class App {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
OuterPoJo myPoJo = objectMapper.readValue(
new File("file.json"),
OuterPoJo.class);
for (TPDetails item : myPoJo.getData()) {
System.out.println(item.getId() + ":" + item.getName());
}
}
}
output:
44:Malgudi ABC
45:Malgudi, DEF

Jackson builder pattern get value from parent

I am trying to obtain a value from a parent node using Jackson.
I know this is possible to achieve with custom deserialisers, but then there is too much boilerplate because you suddenly have to handle everything manually.
It sounds like something quite simple but didn't find a way to do it.
To illustrate what I want - If we have a simple User with Address...
#JsonDeserialize(builder = User.Builder.class)
public class User
{
private long id;
private String firstName;
private Address address;
...
public static class Builder
{
public Builder withId(long id);
public Builder withFirstName(String value);
public Builder withAddress(Address address);
public User create();
}
}
If we have the same for address
#JsonDeserialize(builder = Address.Builder.class)
public class Address
{
...
public static class Builder
{
public Builder withUserId(long id); // is there a way to ask for the parent id here?
public Builder withStreetName(String value);
public Address create();
}
}
Sample input:
{
"id": 7,
"firstName" : "John",
"lastName" : "Smith",
"address" : {
"streetName": "1 str"
}
}
No, I don't think you can with any of the existing Jackson code. The only thing I believe that can cross parent/child relationships like that is type serialization/deserialization and the UNWRAP_ROOT_VALUE support.
If you want something like that, you'd either need to use a custom deserializer for User, or customize the User constructor to build a new address with the correct UserId before adding it to the builder's internal state. Here's an example (using Lombok to handle the boilerplate generation of builders):
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.Builder;
import lombok.Value;
import lombok.experimental.Wither;
public class Scratch {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1234,\"address\":{\"street\":\"123 Main St.\"}}";
User user = mapper.readValue(json, User.class);
System.out.println(user.toString());
}
#Value
#JsonDeserialize(builder = User.UserBuilder.class)
public static class User {
private final int id;
private final Address address;
#Builder(toBuilder = true)
public User(int id, Address address) {
this.id = id;
// Build a new address with the user's ID
this.address = address.withUserId(id);
}
#JsonPOJOBuilder(withPrefix = "")
public static class UserBuilder {}
}
#Value
#Builder(toBuilder = true)
#JsonDeserialize(builder = Address.AddressBuilder.class)
public static class Address {
#Wither
private final int userId;
private final String street;
#JsonPOJOBuilder(withPrefix = "")
public static class AddressBuilder {}
}
}
This consumes the following json:
{
"id": 1234,
"address": {
"street": "123 Main St."
}
}
and produces the following output:
Scratch.User(id=1234, address=Scratch.Address(userId=1234, street=123 Main St.))

How to create POJO for duplicate property name in JSON for Android Retrofit library

I have the following JSON to create POJO and that the POJOs will be used in Android Retrofit library but how to create POJO classes with duplicate JSON property name?
My sample JSON:
{
"result": {
"detail": {
"name": "sample"
}
},
"info": {
"detail": {
"user_information": "user"
}
}
}
Here JSON object detail is duplicated in info and result JSON objects, if I create detail.java for result and detail_.java for info then get null pointer exception from Retrofit library (I hope, get the exception for property name mismatch with pojo classes).
Create pojo like this using inner classes.
public class JsonResponse{
public Result result;
public Info info;
//Getters and Setters
public class Result{
public NameDetails detail;
//Getters and Setters
public class NameDetails{
public String name;
//Getters and Setters
}
}
public class Info{
public UserInfoDetails detail;
//Getters and Setters
public class UserInfoDetails {
public String user_information;
//Getters and Setters
}
}
}
You can use this site to convert json into pojo classes. Secondary you can declare Detail class inside Result class and Info class as a inner class. Example :- View.OnClickListener and DialogInterface.OnClickListener. In this example, OnClickListener interface name is same so we need to write outer class name to distinguish.
For your case, this is json converted by site:-
-----------------------------------com.example.Detail.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Detail {
#SerializedName("name")
#Expose
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
-----------------------------------com.example.Detail_.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Detail_ {
#SerializedName("user_information")
#Expose
private String userInformation;
public String getUserInformation() {
return userInformation;
}
public void setUserInformation(String userInformation) {
this.userInformation = userInformation;
}
}
-----------------------------------com.example.Example.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("result")
#Expose
private Result result;
#SerializedName("info")
#Expose
private Info info;
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
public Info getInfo() {
return info;
}
public void setInfo(Info info) {
this.info = info;
}
}
-----------------------------------com.example.Info.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Info {
#SerializedName("detail")
#Expose
private Detail_ detail;
public Detail_ getDetail() {
return detail;
}
public void setDetail(Detail_ detail) {
this.detail = detail;
}
}
-----------------------------------com.example.Result.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Result {
#SerializedName("detail")
#Expose
private Detail detail;
public Detail getDetail() {
return detail;
}
public void setDetail(Detail detail) {
this.detail = detail;
}
}

Id property is missing in the reponse of a RestAPI call [duplicate]

Have a strange problem and can't figure out how to deal with it.
Have simple POJO:
#Entity
#Table(name = "persons")
public class Person {
#Id
#GeneratedValue
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "middle_name")
private String middleName;
#Column(name = "last_name")
private String lastName;
#Column(name = "comment")
private String comment;
#Column(name = "created")
private Date created;
#Column(name = "updated")
private Date updated;
#PrePersist
protected void onCreate() {
created = new Date();
}
#PreUpdate
protected void onUpdate() {
updated = new Date();
}
#Valid
#OrderBy("id")
#OneToMany(mappedBy = "person", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<PhoneNumber> phoneNumbers = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Date getCreated() {
return created;
}
public Date getUpdated() {
return updated;
}
public List<PhoneNumber> getPhoneNumbers() {
return phoneNumbers;
}
public void addPhoneNumber(PhoneNumber number) {
number.setPerson(this);
phoneNumbers.add(number);
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
#Entity
#Table(name = "phone_numbers")
public class PhoneNumber {
public PhoneNumber() {}
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
#Id
#GeneratedValue
private Long id;
#Column(name = "phone_number")
private String phoneNumber;
#ManyToOne
#JoinColumn(name = "person_id")
private Person person;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
and rest endpoint:
#ResponseBody
#RequestMapping(method = RequestMethod.GET)
public List<Person> listPersons() {
return personService.findAll();
}
In json response there are all fields except Id, which I need on front end side to edit/delete person. How can I configure spring boot to serialize Id as well?
That's how response looks like now:
[{
"firstName": "Just",
"middleName": "Test",
"lastName": "Name",
"comment": "Just a comment",
"created": 1405774380410,
"updated": null,
"phoneNumbers": [{
"phoneNumber": "74575754757"
}, {
"phoneNumber": "575757547"
}, {
"phoneNumber": "57547547547"
}]
}]
UPD Have bidirectional hibernate mapping, maybe it's somehow related to issue.
I recently had the same problem and it's because that's how spring-boot-starter-data-rest works by default. See my SO question -> While using Spring Data Rest after migrating an app to Spring Boot, I have observed that entity properties with #Id are no longer marshalled to JSON
To customize how it behaves, you can extend RepositoryRestConfigurerAdapter to expose IDs for specific classes.
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
#Configuration
public class RepositoryConfig extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Person.class);
}
}
In case you need to expose the identifiers for all entities:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.Type;
#Configuration
public class RestConfiguration implements RepositoryRestConfigurer {
#Autowired
private EntityManager entityManager;
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(
entityManager.getMetamodel().getEntities().stream()
.map(Type::getJavaType)
.toArray(Class[]::new));
}
}
Note that in versions of Spring Boot prior to 2.1.0.RELEASE you must extend the (now deprecated) org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter instead of implement RepositoryRestConfigurer directly.
If you only want to expose the identifiers of entities that extends or
implements specific super class or interface:
...
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(
entityManager.getMetamodel().getEntities().stream()
.map(Type::getJavaType)
.filter(Identifiable.class::isAssignableFrom)
.toArray(Class[]::new));
}
If you only want to expose the identifiers of entities with a specific annotation:
...
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(
entityManager.getMetamodel().getEntities().stream()
.map(Type::getJavaType)
.filter(c -> c.isAnnotationPresent(ExposeId.class))
.toArray(Class[]::new));
}
Sample annotation:
import java.lang.annotation.*;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface ExposeId {}
Answer from #eric-peladan didn't work out of the box, but was pretty close, maybe that worked for previous versions of Spring Boot. Now this is how it is supposed to be configured instead, correct me if I'm wrong:
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
#Configuration
public class RepositoryConfiguration extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(User.class);
config.exposeIdsFor(Comment.class);
}
}
The class RepositoryRestConfigurerAdapter has been deprecated since 3.1, implement RepositoryRestConfigurer directly.
#Configuration
public class RepositoryConfiguration implements RepositoryRestConfigurer {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(YouClass.class);
RepositoryRestConfigurer.super.configureRepositoryRestConfiguration(config);
}
}
Font: https://docs.spring.io/spring-data/rest/docs/current-SNAPSHOT/api/org/springframework/data/rest/webmvc/config/RepositoryRestConfigurer.html
With Spring Boot you have to extends SpringBootRepositoryRestMvcConfiguration
if you use RepositoryRestMvcConfiguration the configuration define in application.properties may not worked
#Configuration
public class MyConfiguration extends SpringBootRepositoryRestMvcConfiguration {
#Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Project.class);
}
}
But for a temporary need
You can use projection to include id in the serialization like :
#Projection(name = "allparam", types = { Person.class })
public interface ProjectionPerson {
Integer getIdPerson();
String getFirstName();
String getLastName();
}
Just add #JsonProperty annotation to the Id and it works.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonProperty
private long id;
another approach is to implement RepositoryRestConfigurerAdapter in configuration. (This approach will be usefull when you have to do marshalling in many places)
#Component
public class EntityExposingIdConfiguration extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
try {
Field exposeIdsFor = RepositoryRestConfiguration.class.getDeclaredField("exposeIdsFor");
exposeIdsFor.setAccessible(true);
ReflectionUtils.setField(exposeIdsFor, config, new ListAlwaysContains());
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
class ListAlwaysContains extends ArrayList {
#Override
public boolean contains(Object o) {
return true;
}
}
}
Hm, ok seems like I found the solution. Removing spring-boot-starter-data-rest from pom file and adding #JsonManagedReference to phoneNumbers and #JsonBackReference to person gives desired output. Json in response isn't pretty printed any more but now it has Id. Don't know what magic spring boot performs under hood with this dependency but I don't like it :)
Easy way: rename your variable private Long id; to private Long Id;
Works for me. You can read more about it here
Implement the RepositoryRestConfigurer and use #Configuration annotation on the class.
Here's the snippet
#Configuration
public class BasicConfig implements RepositoryRestConfigurer{
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
// TODO Auto-generated method stub
config.exposeIdsFor(Person.class);
}
}
You can also use the static configuration method to easily enable exposing ids in a few lines.
From the Spring Data Rest RepsositoryRestConfigurer docs:
static RepositoryRestConfigurer withConfig(Consumer<RepositoryRestConfiguration> consumer)
Convenience method to easily create simple RepositoryRestConfigurer instances that solely want to tweak the RepositoryRestConfiguration.
Parameters:
consumer - must not be null.
Since:
3.1
So this works for me in an existing #Configuration-annotated class:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
#Configuration
public class ApplicationConfiguration {
#Bean
public RepositoryRestConfigurer repositoryRestConfigurer() {
return RepositoryRestConfigurer.withConfig(repositoryRestConfiguration ->
repositoryRestConfiguration.exposeIdsFor(Person.class)
);
}
}

How to serialize ObjectId to JSON?

I want to serialize ObjectId of my Product class to JSON. I got the following JSON:
[{"name":"Play for Java: Covers Play 2","type":"Book","company":"Manning Publications","price":30.0,"imagePath":"public/images/play-for-java.png","rating":4.5,"category":"Computer","author":"Nicolas Leroux","publicationDate":1396224000000,"numPage":320,"_id":539da7a6370882f10d5c2777}]
You can notice that the "_id" didn't be properly serialized, it should be "539da7a6370882f10d5c2777" (with double quotes) and not just 539da7a6370882f10d5c2777.
Therefore, I have tried to implement my own ObjectIdSerializer as following:
import java.io.IOException;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class ObjectIdSerializer extends JsonSerializer<ObjectId> {
#Override
public void serialize(ObjectId value, JsonGenerator jsonGen,SerializerProvider provider) throws IOException,
JsonProcessingException {
jsonGen.writeString(value.toString());
}
}
It gave me the different error: java.lang.String cannot be cast to org.bson.types.ObjectId (through reference chain: models.Book["_id"])
Here are my Product class and Book class:
Product.java
#JsonTypeInfo(use= JsonTypeInfo.Id.CLASS,property="_class")
public class Product {
#ObjectId #Id
#JsonSerialize(using = ObjectIdSerializer.class)
protected String id;
#JsonProperty("name")
protected String name;
#JsonProperty("type")
protected String type;
#JsonProperty("description")
protected String description;
#JsonProperty("company")
protected String company;
#JsonProperty("price")
protected float price;
#JsonProperty("imagePath")
protected String imagePath;
#JsonProperty("imageName")
protected String imageName;
#JsonProperty("rating")
protected float rating;
public Product() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
// Getters and setters
...
Book.java
public class Book extends Product{
#JsonProperty("category")
private String category;
#JsonProperty("author")
private String author;
#JsonProperty("publicationDate")
private Date publicationDate;
#JsonProperty("numPage")
private int numPage;
public Book() {
}
// Getters and setters
...
Can you help me figure it out how can I properly serialize the ObjectId to JSON?
It looks like Jackson has been customized to serialize the string id field in a special way. That is probably a part of the integration with org.bson library.
The problem is that your deserializer is parametrized by the ObjectId type instead of String or plain Object. Try to change it as follows and also remove the #ObjectId annotation from the field declaration. Here is an example:
public class ObjectIdSerializer extends JsonSerializer<Object> {
#Override
public void serialize(Object value, JsonGenerator jsonGen,SerializerProvider provider) throws IOException {
jsonGen.writeString(value.toString());
}
}
You may also consider adopting the Jackson-Jongo provider class to fix the object id serialization for all the classes.

Categories

Resources