I have a class called Customer.
#Entity
#Table(name = "customer")
public class Customer {
#Id
#Column(unique = true)
private String userId;
#Column(unique = true)
private String userName;
private String fullName;
#Column(unique = true)
private String emailAddress;
private String password;
private String country;
#ElementCollection
private Collection<ContactNum> contactNums = new ArrayList<>();
private String district;
private String dateOfBirth;
private String gender;
}
and there is a collection of contact numbers.
#XmlRootElement
#Embeddable
public class ContactNum {
private String landLine;
#Column(unique = true)
private String mobile;
public String getLandLine() {
return landLine;
}
public void setLandLine(String landLine) {
this.landLine = landLine;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
My REST API is getting a POST Request JSON Object which is Customer and Contact number inside it.
{
"userName": "aaaa",
"fullName": "aaaa",
"emailAddress": "aaaa",
"password": "aaaa",
"country": "aaaa",
"contactNums" : {
"landLine": "0000000000",
"mobile": "0000000000"
},
"district": "aaaa",
"dateOfBirth": "813695400000",
"gender": "aaaa"
}
How can I map that request in my JAX-RS client? My method to get request is this. And I also use Hibernate as an ORM tool.
#POST
#Path("registerCustomer")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response registerCustomer(Customer newCustomer) {
}
If you're using Jackson to handle JSON conversion.
You can either use a custom deserializer (via #JsonDeserialize
on class level).
Or write an adapter which converts your ContactNum
to a Collection of ContactNum's.
But if you change your JSON input from
"contactNums" : {
"landLine": "0000000000",
"mobile": "0000000000"
}
to
"contactNums" : [{
"landLine": "0000000000",
"mobile": "0000000000"
}]
(contactNums changed from object to array of objects)
This way the conversion should work out of the box.
Related
I'm learning how to properly use DTOs and so far everything was going well until I got this problem:
I have a Model called Student:
#Data
#Document
#Builder
public class Student {
#Id
private String id;
#Indexed(unique = true)
private Name name;
#Indexed(unique = true)
private String email;
private Gender gender;
private Address address;
private List<String> favoriteSubjects;
private BigDecimal totalSpentInBooks;
private LocalDateTime created;
}
Than I create a DTO to fetch some data:
#Data
public class StudentDto {
private String firstName;
private String lastName;
private String email;
private String country;
}
Here is the response using the DTO from Postman:
{
"firstName": "Gabriel",
"lastName": "Vendramini",
"email": "gabriel.vendramini#email.com",
"country": null
}
Here is the same response but with no DTO:
{
"id": "61f7d87bb4534b452993b02e",
"name": {
"firstName": "Gabriel",
"lastName": "Vendramini"
},
"email": "gabriel.vendramini#email.com",
"gender": "MALE",
"address": {
"country": "Brazil",
"city": "Sao Paulo",
"postCode": "08006"
},
"favoriteSubjects": [
"Computer Science",
"Mathematic",
"Physic"
],
"totalSpentInBooks": 10,
"created": "2022-01-31T13:39:23.023"
}
Here are the Controller:
#GetMapping("/get-all")
public ResponseEntity<List<Student>> fetchAllStudents() {
log.info("Get All Students - Controller Call");
return ResponseEntity.ok(studentService.getAllStudents());
}
#GetMapping("/get-all-dto")
public ResponseEntity<List<StudentDto>> fetchAllStudentsDto() {
log.info("Get All Students With DTO - Controller Call");
return ResponseEntity.ok(studentService.getAllStudents().stream().map(studen
t -> modelMapper.map(student,
StudentDto.class)).collect(Collectors.toList()));
}
Here are the Models for Address and Name:
#Data
#AllArgsConstructor
#Builder
public class Address {
private String country;
private String city;
private String postCode;
}
#Data
#AllArgsConstructor
#Builder
public class Name {
private String firstName;
private String lastName;
}
The structure is the same for both. I tried to pass all the attributes from Address, change the order.
I want to create this JSON using jakson annotated POJOS. The issue I have when I create a new class without #JsonProperty annotation to represent the last {"id":"123ccc","role":"dddd"}, it by default take the class name and create something like "customer":{"id": "123ccc","role":"dddd"}.
The JSON Structure I indent to build
{
"relatedParty": [
{
"contact": [
{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
},
{
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}
],
"role": "ccc",
"fullName": "ccc"
},
{
"id": "123ccc",
"role": "dddd"
}
]
}
The JSON I'm receiving from the below code.
{
"relatedParty": [
{
"contact": [
{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
},
{
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}
],
"role": "ccc",
"fullName": "ccc"
},
"customer" : {
"id": "123ccc",
"role": "dddd"
}
]
}
What would be a workaround to get the exact JSON format as the image. Current Implementation is below.
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class RelatedParty {
#JsonProperty(value = "contact")
private List<Contact> contact;
#JsonProperty(value = "role")
private String role;
#JsonProperty(value = "fullName")
private String fullName;
private Customer customer;
public List<Contact> getContact() {
return contact;
}
public void setContact(List<Contact> contact) {
this.contact = contact;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
public class Customer {
#JsonProperty(value = "id")
private String id;
#JsonProperty(value = "role")
private String role;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
You need to create additional and different POJO classes to model your JSON correctly. Basically, JSON arrays will be handle in Java lists, and JSON objects will be handled in Java classes.
Starting from the inside (most nested level) of the JSON, and working our way out:
NOTE: getters and setters not shown here
Characteristic.java
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Characteristic {
#JsonProperty("city")
private String city;
#JsonProperty("country")
private String country;
#JsonProperty("emailAddress")
private String emailAddress;
}
Contact.java (contains our characteristics):
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Contact {
#JsonProperty("mediumType")
private String mediumType;
#JsonProperty("characteristic")
private Characteristic characteristic;
}
The above two classes handle the innermost objects. If we remove them from your target JSON, that leaves the following:
{
"relatedParty": [{
"contact": [...],
"role": "ccc",
"fullName": "ccc"
}, {
"role": "dddd",
"id": "123ccc"
}]
}
Note that the contact field is a JSON array, not an object - so we do not create a Java Contact class (which would be for a JSON object).
To handle the above I create two more classes:
RelatedPartyInner.java (contains a list of contacts)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class RelatedParty_ {
#JsonProperty("contact")
private List<Contact> contact = null;
#JsonProperty("role")
private String role;
#JsonProperty("fullName")
private String fullName;
#JsonProperty("id")
private String id;
}
RelatedParty.java (wraps everything in an outer object):
#JsonInclude(JsonInclude.Include.NON_NULL)
public class RelatedParty {
#JsonProperty("relatedParty")
private List<RelatedPartyInner> relatedParty = null;
}
To test this I create the following data:
Characteristic chr1 = new Characteristic();
chr1.setCity("xxx");
chr1.setCountry("xxx");
Characteristic chr2 = new Characteristic();
chr2.setEmailAddress("yyy#yy.yyy");
Contact con1 = new Contact();
con1.setMediumType("xxx");
con1.setCharacteristic(chr1);
Contact con2 = new Contact();
con2.setMediumType("yyy");
con2.setCharacteristic(chr2);
List<Contact> cons = new ArrayList<>();
cons.add(con1);
cons.add(con2);
RelatedPartyInner rpi1 = new RelatedPartyInner();
rpi1.setContact(cons);
rpi1.setRole("ccc");
rpi1.setFullName("ccc");
RelatedPartyInner rpi2 = new RelatedPartyInner();
rpi2.setId("123ccc");
rpi2.setRole("dddd");
List<RelatedPartyInner> rpis = new ArrayList<>();
rpis.add(rpi1);
rpis.add(rpi2);
RelatedParty rp = new RelatedParty();
rp.setRelatedParty(rpis);
Finally, we can generate the JSON:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(new File("rp.json"), rp);
The resulting file contains the following:
{
"relatedParty": [{
"contact": [{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
}, {
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}],
"role": "ccc",
"fullName": "ccc"
}, {
"role": "dddd",
"id": "123ccc"
}]
}
I am writing an annotation processor and i need to scan all classes with certain annotation to get all fields and create json object with same structure of the class.
For example:
#ClassToJson
public class Person {
private String name;
private String surname;
/*getter and setter*/
}
My output is:
{
"name": "string",
"surname": "string"
}
Now i am wondering how can i handle classes like this one:
public class PhoneNumber {
private String countryCode;
private String phoneNumber;
/*getter and setter*/
}
#ClassToJson
public class Person {
private String name;
private String surname;
private PhoneNumber phoneNumber;
/*getter and setter*/
}
i would like get output like this:
{
"name": "string",
"surname": "string",
"phoneNumber": {
"countryCode": "string",
"phoneNumber": "string"
}
}
I am making a restaurant management app and I am having a problem persisting a user association. For the Chef class there is a set association with the Dish class so that specific dishes can be associated with a certain chef.
I have created a method that associates a dish with a chef, and when I try calling it on my REST client the method seems to work, and it returns a JSON of the chef object with the updated info, however when I call the get chef method the JSON no longer shows the added dish item
Here is the chef class and everything related to the Dish Object
#Table(name="chef")
public class Chef {
//Chef Attributes
#Id private String username;
private String firstName;
private String lastName;
private String email;
private String password;
private String address;
private String bio;
private Boolean delivery;
private String photoURL;
// #OneToOne
// private ChefMenu menu;
#Transient
#OneToMany(mappedBy = "chef", cascade = CascadeType.ALL)
#JsonIgnoreProperties("chef")
private Set<Dish> menuItems;
public Set<Dish> getMenuItems() {
if (this.menuItems == null) {
this.menuItems = new HashSet<Dish>();
}
return this.menuItems;
}
Here is the Dish class with everything related to the Chef class
#Entity
#Table(name="dish")
public class Dish {
//Dish Attributes
#Id private String dishName;
private String cuisine;
private double price;
private String maxQuantity;
private String dietaryRestriction;
private String mealIngredients;
private String cookingTime;
#ManyToOne
#JoinColumn(name = "chef")
#JsonIgnoreProperties({"menuItems","orders","firstName", "lastName", "email", "bio", "password", "address", "delivery", "photoURL"})
private Chef chef;
public void setChef(Chef val) { this.chef = val; }
public Chef getChef() {
return this.chef;
}
Here is the method used to add a new dish to a chef from the repository
#Transactional
public Chef addDishToMenu(Chef c, Dish d) {
c.addDish(d);
entityManager.merge(c);
return c;
}
And finally here is code from the controller class:
#PostMapping("dish/create/{dishName}/{cuisine}/{price}/{maxQuantity}/{dietaryRestriction}/{mealIngredients}/{cookingTime}")
public ResponseEntity createDish(String username,
#PathVariable("dishName") String dishName, #PathVariable("cuisine") String cuisine,
#PathVariable("price") String price, #PathVariable("maxQuantity") String maxQuantity,
#PathVariable("dietaryRestriction") String dietaryRestriction,
#PathVariable("mealIngredients") String mealIngredients, #PathVariable("cookingTime") String cookingTime)
{
Dish d = new Dish();
Double p = Double.parseDouble(price);
//int mQ = Integer.parseInt(maxQuantity);
try {
d = foodRepository.createDish(dishName, cuisine, p, maxQuantity, dietaryRestriction,
mealIngredients, cookingTime);
} catch (InvalidInputException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new Response(false, e.getMessage()));
}
return ResponseEntity.status(HttpStatus.OK).body(d);
}
#PostMapping("dish/add/{username}/{dishName}")
public ResponseEntity addDishToMenu(#PathVariable("username") String username, #PathVariable("dishName") String dishName) throws NullObjectException {
Chef c = new Chef();
Dish d = new Dish();
c= chefRepository.getChef(username);
d = foodRepository.getSpecificDish(dishName);
c = foodRepository.addDishToMenu(c, d);
return ResponseEntity.status(HttpStatus.OK).body(c);
}
#GetMapping("/get/{username}")
public ResponseEntity getChef(#PathVariable("username") String username) {
// List<AppUser> user;
Chef chef = new Chef();
try {
chef = chefRepository.getChef(username);
// user = userRepository.getAppUserQuery(username);
} catch (NullObjectException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new Response(false, e.getMessage()));
}
return ResponseEntity.status(HttpStatus.OK).body(chef);// user.get(0));
}
So when I make the call on my Rest client to add a dish to a chef I get this as a response:
{
"username": "Favreau4",
"firstName": "Jon",
"lastName": "Favreau",
"email": "chefFavreau#email.com",
"password": "j+9UECq/PLA=$I+HsXngf/b82+rMtPQQO",
"address": null,
"bio": null,
"delivery": null,
"photoURL": null,
"menuItems": [
{
"dishName": "Big sandwich",
"cuisine": "american",
"price": 5,
"maxQuantity": "3",
"dietaryRestriction": "bacon",
"mealIngredients": "bacon,lettuce,tomato,bread",
"cookingTime": "10mins"
}
],
"order": [],
}
but when I use the getChef REST call I get this:
{
"username": "Favreau4",
"firstName": "Jon",
"lastName": "Favreau",
"email": "chefFavreau#email.com",
"password": "j+9UECq/PLA=$I+HsXngf/b82+rMtPQQO",
"address": null,
"bio": null,
"delivery": null,
"photoURL": null,
"menuItems": [],
"order": [],
}
Does anyone know how to resolve this issue?
Are you aware of #Transient annotation? Transient are used to mark a variable as non-presistable. So your menuitems are not getting persist or saved in database.
We have such object:
#JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
#Document(collection = Order.COLLECTION_NAME)
public class Order implements Serializable {
public static final String COLLECTION_NAME = "orders";
#Id
private Long id;
private Long orgId;
private Long userId;
private Date creationDate = new Date();
private Integer statusCode = Status.NEW.code();
private Integer typeCode;
private Integer paymentCode;
private Date date;
private String phoneNumber;
private List<UserAddressList> userAddressList;
private BigDecimal cash;
private Integer persons;
private String comments;
private List products;
#Indexed(unique = true)
private String token = UUID.randomUUID().toString();
private Boolean deleted = Boolean.FALSE;
In this object we have two Lists which contains 2 another objects:
private List userAddressList;
private List products;
public class UserAddressList implements Serializable {
private String street;
private String house;
private String building;
private Long flat;
private Long entrance;
private Long floor;
private String intercom;
public class ProductPack implements Serializable {
private Long productId;
private Integer quantity;
public ProductPack() {
}
public ProductPack(Long productId, Integer quantity) {
this.productId = productId;
this.quantity = quantity;
}
We have such api method for adding new order:
#RequestMapping(value = "/add", method = RequestMethod.POST)
public #ResponseBody ResponseDto addOrder(
#RequestHeader(value = "Authorization") String authorization,
#RequestBody final Order order) {
When we send this JSON to the server:
{"statusCode": 0,
"typeCode": 1,
"paymentCode": 4,
"date": 2430919020590,
"phoneNumber": "+79216450091",
"userAddressList":
[{
"street": "Test",
"house": "House",
"building": "A",
"entrance": 1,
"floor": 8,
"intercom": "intercom",
"flat": 12
}]
,
"persons": 1,
"products":
[{
"productId": 97,
"quantity": 5
}
]}
it returns "The request sent by the client was syntactically incorrect"
when we send this JSON:
{"statusCode": 0,
"typeCode": 1,
"paymentCode": 4,
"date": 2430919020590,
"phoneNumber": "+79216450091",
"persons": 1,
"products": [
{
"productId": 97,
"quantity": 5
}
]}
server accepts it but userAddressList is null
Can you please help to figure out the problem?
Check conformity between your fields in the JSON-request and in the code. It is possible that field you have declared is not that field that servers maps. For example UserAddressList could be address.