Rename fields in response dto. Java, Spring - java

I have the following question. I want to rename fields in JSON response. In my DTO fields are defined in camal case. In response json a want to use separate words with underscores. I tried to use #JsonPropperty annotation but it is not working. My DTO class is below:
package com.example.demo.dto.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
#Data
public class UserResponseDto {
private String id;
private String name;
#JsonProperty("second_name")
private String secondName;
private String email;
private String login;
private String password;
#JsonProperty("date_of_birth")
private Date dateOfBirth;
#JsonProperty("date_of_registration")
private Date dateOfRegistration;
private Set<RoleResponseDto> roles = new HashSet<>();
}
And the response is still in camal case:
{
"id": "d6c0873b-166b-4d6f-90b4-91d9f0dfa0a0",
"name": "Simon",
"secondName": "Wilder",
"email": "myNewEmail#gmail.com",
"login": "QMY",
"password": "$2a$10$Lj3EctARwD34EInzmwsjjuTsKiOzKtI7Gf7pskUfxcPt1PNRDHF1m",
"dateOfBirth": "1991-12-21T00:00:00.000+00:00",
"dateOfRegistration": "2022-04-07T12:52:24.059+00:00",
"roles": [
{
"id": "a9cc27ba-532a-456a-a9b5-ad14052190f8",
"title": "ROLE_USER"
},
{
"id": "684bf3b6-721d-494c-9c66-caeee44933d2",
"title": "ROLE_ADMIN"
}
]
}
Do You have any ideas? Or it is a bug, or what? Everywhere it is written to use #JsonPropperty annotation.

So there are 2 ways to do what you want but first make sure you are using #ResponseBody on all your Controller methods or make sure your controller classes are using #RestController.
if you want the whole application to use the underscore case in the response body then add this to your configs:
Gson Method
#Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(createGsonHttpMessageConverter());
super.addDefaultHttpMessageConverters(converters);
}
#Bean
public Gson createGson() {
return new GsonBuilder().disableHtmlEscaping()
.serializeNulls()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
}
#Bean
public GsonHttpMessageConverter createGsonHttpMessageConverter() {
GsonHttpMessageConverter gsonConverter = new GsonHttpMessageConverter();
gsonConverter.setGson(createGson());
return gsonConverter;
}
}
Reference
Jackson Method
spring.jackson.property-naming-strategy=SNAKE_CASE
Reference:
if you want it on a single DTO then you can use
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
Refercences:

Related

Embedded and Embeddable data not stored in the database

I am Learning java-spring boot and i was able to store the normal data in db. but i wasn't able to store the complex json data.
the json data:
{
"id": 1,
"name": "Leanne Graham",
"address": {
"street": "Kulas Light",
"city": "Gwenborough"
}
}
User.java
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
#Data
#AllArgsConstructor
#Entity
#Table(name = "User_tbl")
public class User {
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Long id;
private String name;
#Embedded
#Column(name = "Address")
private Address address;
}
Address.java
import jakarta.persistence.Embeddable;
import lombok.AllArgsConstructor;
import lombok.Data;
#Data
#AllArgsConstructor
#Embeddable
public class Address {
private String street;
private String city;
}
UserController.java
import com.example.JsonParser.model.User;
import com.example.JsonParser.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class UserController {
#Autowired
private UserService userService;
#GetMapping("/list")
public Iterable<User> list() {
return userService.list();
}
#PostMapping("/add")
public User save(User user){
return userService.add(user);
}
}
UserRepository.java
import com.example.JsonParser.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends JpaRepository<User,Long> {
}
UserService.java
import com.example.JsonParser.model.User;
import com.example.JsonParser.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class UserService {
#Autowired
private UserRepository repo;
public Iterable<User> list() {
return repo.findAll();
}
public Iterable<User> save(List<User> users) {
return repo.saveAll(users);
}
public User add(User user) {
repo.save(user);
return user;
}
}
application.yml
spring:
h2:
console:
enabled: 'true'
datasource:
url: jdbc:h2:mem:Ramesh
jpa:
defer-datasource-initialization: 'true'
when i send the post request with json data
{
"id": 1,
"name": "Leanne Graham",
"address": {
"street": "Kulas Light",
"city": "Gwenborough"
}
}
i got response as
{
"id": 1,
"name": null,
"address": null
}
H2 db:
also, the db is empty what i should modify or add in order to store the data?
The first thing is that the data from the request is not reaching the Controller. If you put a breakpoint in your save method you can see that all the attributes inside the User will be null. So the first thing you need to do is to annotate the method argument with this #RequestBody, so automatically the JSON data will be converted to your Bean (given that the fields are having the same name).
#PostMapping("/add")
public User save(#RequestBody User user){
return userService.add(user);
}
Second thing is that both your User and Address class should be annotated with #NoArgsConstructor.
So once you've done both the issue will be solved, and data will be saved and retrieved properly.
As you have created Two Entity Classes. First, you have to save the Address and then take Address Instance and set it in the User Entity class and then save it.
OR
Make address as a string instead of Entity class and Try to Pass the data as JSON String to the controller so that I will save it as JSON String
public class User {
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Long id;
private String name;
private String address;
}
{
"id": 1,
"name": "Leanne Graham",
"address": "{ "street": "Kulas Light", "city": "Gwenborough" }"
}

How to save array of object in sprig boot with crudrepository?

I am very new to Spring boot and this is my first spring dummy project where I'm trying to learn to save an array of objects in mysql-db.
Actually, I am trying to use the saveAll method from the crudRepository in my controller. But it's giving me an error no instance(s) of type variable(s) S exist so that Iterable<S> conforms to List<User>
My JSON looks like this:
[
{
"first_name": "Jack",
"last_name": "Jill",
"email": "jacjill#gmail.com",
"password": "passq3623"
},
{
"first_name": "John",
"last_name": "Doe",
"email": "john#gmail.com",
"password": "pass23"
}
]
This is my entity class
package com.example.testbatch.Entities;
import javax.persistence.*;
#Entity
#Table(name = "user")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int id;
public String first_name;
public String last_name;
public String email;
public String password;
}
Here is my User Model Class
package com.example.testbatch.Models;
public class User {
public int id;
public String firstName;
public String lastName;
public String email;
public String password;
}
Here is my repository
package com.example.testbatch.Repositories;
import com.example.testbatch.Entities.UserEntity;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface UserRepository extends CrudRepository<UserEntity, Integer> {
#Override
List<UserEntity> findAll();
}
and here is my rest controller
package com.example.testbatch.Controllers;
import com.example.testbatch.Entities.UserEntity;
import com.example.testbatch.Models.User;
import com.example.testbatch.Repositories.UserRepository;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
#RestController
#RequestMapping("/api/v1/user")
public class UserController {
#Autowired
UserRepository userRepository;
#PostMapping("/register")
public void saveUsers(#RequestBody UserEntity userEntity) {
List<User> persistedUser = userRepository.saveAll(List.of(userEntity));
}
}
Can anyone please help me? This is ery first time I am usig spring boot
You have some problems about your code:
At first you have a DTO (User class), so, you should use this DTO inside your controller in saveUsers method and more importantly you pass an array of objects in your JSON, so you have to use a List not an Object as the parameter:
public void saveUsers(#RequestBody List<User> users) {...}
Another problem is you don't have any getters and setters inside you DTO (public class User) and Entity (public class UserEntity) classes and also you have to add a method inside your DTO class for mapping DTO to Entity:
public class User {
...
public static UserEntity dtoToEntity(User user){
UserEntity userEntity = new UserEntity();
userEntity.setEmail(user.getEmail());
userEntity.setPassword(user.getPassword());
userEntity.setFirst_name(user.getFirstName());
userEntity.setLast_name(user.getLastName());
return userEntity;
}
}
Also you must change your JSON properties to match your DTO's properties:
[
{
"firstName": "Jack",
"lastName": "Jill",
...
},
...
]
As the last one, change your controller saveUsers method as (saveAll method return Iterable not List):
#PostMapping("/register")
public void saveUsers(#RequestBody List<User> users) {
List<UserEntity> userEntities = new ArrayList<>();
for (User user : users) {
userEntities.add(dtoToEntity(user));
}
Iterable<UserEntity> persistedUser = userRepository.saveAll(userEntities);
}
Notice: As a point remember that because you have auto-generated id inside your Entity, so you don't need id property for your DTO, obviously because it's auto-generated and you don't need to get it from input;
The user_repo is returning a List of type UserEntity
while in yout controller you are asking for a List of type User
There is not mapping between UserEntity and User.

I send request in post body in springboot it is not working

I'm trying to post body in RESTAPI using spring boot but I cannot. I suffered for long hours till now I also could not find the problem why what is the reason I do not know what mistake I made please help me.
Pojo class
Person.java
package com.thila.family.test;
import javax.annotation.Generated;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Person {
#Id
private int id;
private String familyName;
private String familyMembers;
private long contactNo;
public Person() {
}
public Person(int id,String familyName, String familyMembers,long contactNo) {
super();
this.familyName = familyName;
this.familyMembers = familyMembers;
this.contactNo = contactNo;
}
//getters setters
}
PersonService.java
package com.thila.family.test;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
#Service
public class PersonService {
private List<Person> persons=new ArrayList<>();
public void addPerson(Person person) {
persons.add(person);
}
}
PersonController.java
#RestController
public class PersonController {
#Autowired
private PersonService personService;
#RequestMapping(method=RequestMethod.POST,value="/fam")
public void addPerson(#RequestBody Person person){
personService.addPerson(person);
}
}
My JSON request to the body
{
"id":"1",
"familyName": "panchala",
"familyMembers":"5",
"contactNo":"234567"
}
I got an error
{
"timestamp": "2021-01-02T04:39:55.307+00:00",
"status": 404,
"error": "Not Found",
"message": "",
"path": "/fam"
}
```
please help me I don't know why I got this error
In PersonController.java add the following annotation just below the #RestController annotation:
#RequestMapping(value = "/person", produces = MediaType.APPLICATION_JSON_VALUE)
Only if this is present the controller gets resolved and the path reaches the particular controller method you are trying to call.
Now your URL might look like this : localhost:8080/person/fam
In the Controller class
#RequestMapping(value = "/fam", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void addPerson(#RequestBody Person person){
{
....
}
Just a suggestion it would be also good to return a response with a correct Response status
#RequestMapping(value = "/fam", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity addPerson(#RequestBody Person person){
{
......
return new ResponseEntity<>(HttpStatus.OK);
}
I had the same issue and I was not figuring out how to solve it, but I decided to see my imports, in case of imports being wrong.
I was importing #RequestBody from:
io.swagger.v3.oas.annotations.parameters.RequestBody;
Instead of importing the #RequestBody from:
org.springframework.web.bind.annotation.*
If any question, just comment.

IDE does not show getters and setters generated by Lombok for a Jackson annotated class

I use Intellij Idea 2019.1.2 community edition for my Java projects. I have a Jackson 2.9.6 annotated POJO which uses Lombok 1.18.0 to generate the getters and setters for the pojo. I have some "client" code to deserialize a sample Json text to the Pojo class. The deserialization works fine, without any compilation issues and the class file for the pojo actually has all the getters and setters. But, the IDE does not show any getters and setters for the pojo in the "client" code.
Invalidating the caches of the IDE and restarting it did not solve the problem. How do I find out the cause for this problem and fix it ?
Sample Json :
{
"id": "1234",
"number" : 1,
"items" : [
{
"item1" : "blah...more fields."
},
{
"item2" : "blah...more fields."
}
],
"someBigObject:" : {
"my_comment" : "i don't really care about validating this object.",
"fields" : "more fields here",
"objects" : "more objects here"
},
"message" : "hello"
}
Pojo for above Json, generated by http://www.jsonschema2pojo.org/ :
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"id",
"number",
"items",
"someBigObject:",
"message"
})
#Data
#NoArgsConstructor
public class Example {
#JsonProperty("id")
#NonNull public String id;
#JsonProperty("number")
public Long number;
#JsonProperty("items")
public List<Item> items = null;
#JsonProperty("someBigObject:")
public Object someBigObject;
#JsonProperty("message")
public String message;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"item1",
"item2"
})
#Data
#NoArgsConstructor
public static class Item {
#JsonProperty("item1")
public String item1;
#JsonProperty("item2")
public String item2;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
}
Sample code to try the above pojo :
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class JunkTest {
public static void main(String [] args) throws IOException {
String json = "Put the json here !!!";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
Example pojo = mapper.readValue(json, Example.class);
pojo.getClass();//Cannot see any other getters and setters !
}
}
To resolve this problem you need :
1 - Lombok plugin is installed in Intellij IDEA.
https://projectlombok.org/setup/intellij
Add the Lombok IntelliJ plugin to add lombok support for IntelliJ:
Go to File > Settings > Plugins
Click on Browse repositories...
Search for Lombok Plugin
Click on Install plugin
Restart IntelliJ IDEA
2 - Annotation processing is turned on for your project.
Refer - https://stackoverflow.com/a/27430992

REST Web service JSON format

I am trying to create a REST web service that returns the details of a user.
Here is my code:
//Actual web service methods implemented from here
#GET
#Path("login/{email}/{password}")
#Produces("application/json")
public Tourist loginUser(#PathParam("email") String email, #PathParam("password") String password) {
List<Tourist> tourists = super.findAll();
for (Tourist tourist : tourists) {
if (tourist.getEmail().equals(email) && tourist.getPassword().equals(password)) {
return tourist;
}
}
//if we got here the login failed
return null;
}
This produces the following JSON:
{
"email": "adrian.olar#email.ro",
"fname": "Adrian",
"lname": "Olar",
"touristId": 1
}
What i need is:
{"tourist":{
"email": "adrian.olar#email.ro",
"fname": "Adrian",
"lname": "Olar",
"touristId": 1
}
}
What would i need to add to my code to produce this?
If you really want to wrap a Tourist into another object, you can do this.
Tourist.java:
package entities;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Tourist {
int touristId;
String email;
String fname;
String lname;
TouristWrapper.java:
package entities;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class TouristWrapper {
Tourist tourist;
SOResource.java:
package rest;
import entities.Tourist;
import entities.TouristWrapper;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
#Path("/so")
public class SOResource {
#GET
#Path("/tourists/{id}")
#Produces("application/json")
public TouristWrapper loginUser(#PathParam("id") int id) {
Tourist tourist = new Tourist(id, "foo#example.com", "John", "Doe");
TouristWrapper touristWrapper = new TouristWrapper(tourist);
return touristWrapper;
}
}
I have simplified your usecase but you get the point: No Tourist is returned but a TouristWrapper. The JSON returned is this:
{
"tourist": {
"email": "foo#example.com",
"fname": "John",
"lname": "Doe",
"touristId": 1
}
}

Categories