This question already has answers here:
Annotation for binding a json field to a field in POJO with a different name
(2 answers)
Closed 6 years ago.
Hello I'd like to know how I could mapp my json message to object in java when using spring boot.
Let's say I'm getting json like
{
"customerId": 2,
"firstName": "Jan",
"lastName": "Nowak",
"town": "Katowice"
}
and I'd like to make it entity in my java program:
and for whatever reason I dont want to have match on field names
public class Customer {
//Something like #Map("customerId")
private long OMG;
//Something like #Map("firstName")
private String WTF;
//Something like #Map("lastName")
private String LOL;
//Something like #Map("town")
private String YOLO;
I cannot find what annotation I should use, Not using jackson, just built in spring boot converter??
Spring boot comes with Jackson out-of-the-box.
You can use #RequestBody Spring MVC annotation to un-marshall json string to Java object... something like this.
#RestController
public class CustomerController {
//#Autowired CustomerService customerService;
#RequestMapping(path="/customers", method= RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public Customer postCustomer(#RequestBody Customer customer){
//return customerService.createCustomer(customer);
}
}
Annotate your entities member elements with #JsonProperty with corresponding json field names.
public class Customer {
#JsonProperty("customerId")
private long OMG;
#JsonProperty("firstName")
private String WTF;
#JsonProperty("lastName")
private String LOL;
#JsonProperty("town")
private String YOLO;
}
Spring Boot does grouping dependencies, glue and default configuration. It is not a serialization api. You should use Jackson to perform your need
You shoud map your class such as :
public class Customer {
#JsonProperty("customerId")
private long OMG;
#JsonProperty("firstName")
private String WTF;
#JsonProperty("lastName")
private String LOL;
#JsonProperty("town")
private String YOLO;
....
}
From JsonProperty annotation Javadoc :
Marker annotation that can be used to define a non-static method as a
"setter" or "getter" for a logical property (depending on its
signature), or non-static object field to be used (serialized,
deserialized) as a logical property.
Default value ("") indicates that the field name is used as the
property name without any modifications, but it can be specified to
non-empty value to specify different name. Property name refers to
name used externally, as the field name in JSON objects.
Related
I need to ignore the field when return the response from spring boot. Pls find below info,
I have one pojo called Student as below
Student {
id,
name,
lastName
}
i am getting a body for as PostRequest as below
{
id:"1",
name:"Test",
lname:"Test"
}
i want get all the data from frontEnd (id,name,Lname) But i just want to return the same pojo class without id as below,
{
name:"Test",
lName:"Test"
}
I have tried #JsonIgnore for column id, But it makes the id column as null(id=null -it is coming like this even when i send data to id field from postman) when i get the data from frontEnd.
I would like to use only one pojo to get the data with proper data(withoud getting id as Null), and need to send back the data by ignoring the id column.
Is there any way to achieve it instead of using another pojo?
You just need to use #JsonInclude(JsonInclude.Include.NON_NULL) at class level and it will be helpful for ignore all your null fields.
For example :
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Test {
// Fields
// Constructors
// Getters - setters
}
As of now you are using only one POJO it's not good practice because it's your main entity into your project, so good practice is always make DTO for the same.
This is possible via the #JsonView annotation that is part of Jackson. Spring can leverage it to define the views used on the controller.
You'd define your DTO class like this:
class User {
User(String internalId, String externalId, String name) {
this.internalId = internalId;
this.externalId = externalId;
this.name = name;
}
#JsonView(User.Views.Internal.class)
String internalId;
#JsonView(User.Views.Public.class)
String externalId;
#JsonView(User.Views.Public.class)
String name;
static class Views {
static class Public {
}
static class Internal extends Public {
}
}
}
The Views internal class acts as a marker to jackson, in order to tell it which fields to include in which configuration. It does not need to be an inner class, but that makes for a shorter code snippet to paste here. Since Internal extends Public, all fields marked with Public are also included when the Internal view is selected.
You can then define a controller like this:
#RestController
class UserController {
#GetMapping("/user/internal")
#JsonView(User.Views.Internal.class)
User getPublicUser() {
return new User("internal", "external", "john");
}
#GetMapping("/user/public")
#JsonView(User.Views.Public.class)
User getPrivateUser() {
return new User("internal", "external", "john");
}
}
Since Spring is aware of the JsonView annotations, the JSON returned by the /public endpoint will contain only externalId and name, and the /internal endpoint will additionally include the internalId field.
Note that fields with no annotation will not be included if you enable any view. This behaviour can be controlled by MapperFeature.DEFAULT_VIEW_INCLUSION, which was false in the default Spring ObjectMapper when I used this for the last time.
You can also annotate your #RequestBody parameters to controller methods with JsonView, to allow/disallow certain parameters on input objects, and then use a different set of parameters for output objects.
Im trying to use the restTemplate.postForObject(URL, Session.class) method and map the response to a POJO. This works partially, however when i try to access an element with a name like "name-with-dashes" I cannot find the element.
The JSON I am extracting from the method call:
{"age":60,"expire":12345,"name-with-dashes":"This name has dashes?!"...}
Here is the POJO im using to extract this data:
#Getter
#Setter
#JsonIgnoreProperties(ignoreUnknown = true)
public class Session {
private int age;
private long expire;
//will not grab name-with-dashes... returns null
private String nameWithDashes;
}
You should annotate your fields, especially the ones that do not comply to bean naming conventions, with the #JsonProperty annotation as follows:
#JsonProperty("name-with-dashes")
private String nameWithDashes;
You can annotate the property
#SerializedName("name-with-dashes")
private String nameWithDashes;
using Gson
I have a springboot application which is hitting raw api's of the datasource. Now suppose I have a Customer entity with approx 50 fields and I have a raw api for it in which I pass names of the columns and I get the values for that column. Now I am implementing api in springboot which consumes raw api.
I need to implement different api's in springboot for different combinations of the fields of Customer entity and return only those fields setted in object for which user had queried and remove the null valued fields from the object. One way is to implement different dto's for different combinations of the columns of Customer entity. Is there any other way to implement the same in which I don't need to define different dto's for different combinations of the columns of Customer entity in Spring boot ???
You can configure the ObjectMapper directly, or make use of the #JsonInclude annotation:
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
OR
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Customer {
private Long id;
private String name;
private String email;
private String password;
public Customer() {
}
// getter/setter ..
}
You can see how to do it with this sample code:
Customer customer = new Customer();
customer.setId(1L);
customer.setName("Vikas");
customer.setEmail("info#vikas.com");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String valueAsString = objectMapper.writeValueAsString(customer);
Since the password is left null, you will have an object that does not exist password.
{
"id": 1,
"name": "Vikas",
"email": "info#vikas.com"
}
with Jackson 2.0 serialization you can specify data inclusion on non nulls at different levels, i.e. on the object mapper (with constructor options), the DTO class or DTO class fields (with annotations).
See Jackson annotations here
This can be done using #JsonInclude inside the DTO class. Please refer following code block for ignoring null values.
#JsonInclude(Include.NON_NULL) // ignoring null values
#Data //lombock
#Builder //builder pattern
public class Customer {
private Long id;
private String name;
private String email;
private String password;
}
So far in my Java code with Spring Boot I was using models, or POJO objects to achieve better control of my objects, etc. Usually I am creating Entities, Repositories, Services, Rest controllers, just like documentation and courses are suggesting.
Now however I am working with Thymeleaf templates, HTML a bit of Bootstrap and CSS in order to create browser interface. For methods in #Controller, as parameter, I am passing Model from Spring Model UI like this:
#GetMapping("/employees")
private String viewAllEmployees(Model employeeModel) {
employeeModel.addAttribute("listEmployees", employeeService.getAllEmployees());
return "employeeList";
}
My question is: How can I use my POJO objects instead of org.springframework.ui.Model;?
My first guess was this:
public class EmployeeModel implements Model{
private long employeeId;
private String firstName;
private String lastName;
private String email;
private String phone;
private long companyId;
//getter and setter methods
}
And in order to do that I have to #Override Model methods which is fine with me. And it looks like Java, Spring etc. does not complain in compile time, and I can use this POJO object in my #Controller like this:
#Controller
public class EmployeeController {
#Autowired
private EmployeeService employeeService;
#GetMapping("/employees")
private String viewAllEmployees(EmployeeModel employeeModel) {
employeeModel.addAttribute("listEmployees", employeeService.getAllEmployees());
return "employeeList";
}}
I run the code and it starts, shows my /home endpoint which works cool, however when I want to go to my /employees endpoing where it should show my eployees list it throws this:
Method [private java.lang.String com.bojan.thyme.thymeApp.controller.EmployeeController.viewAllEmployees(com.bojan.thyme.thymeApp.model.EmployeeModel)] with argument values:[0] [type=org.springframework.validation.support.BindingAwareModelMap] [value={}] ] with root cause java.lang.IllegalArgumentException: argument type mismatch
exception.
Please note that Rest controller is working perfectly in browser and Postman.
Is it possible that String as a method is the problem? Should my method be of some other type like List<EmployeeModel> or maybe EmployeeModel itself? If it is so, how to tell the method that I want my employeeList.html to be returned?
I sincerely hope that someone can halp me with this one :)
How can I use my POJO objects instead of org.springframework.ui.Model;?
I don't think that is the best practice when you are working with Thymeleaf. According to their documentation, you should attach your Objects to your Model. So in your controller you would be manipulating models that contain your Pojos.
Example:
#RequestMapping(value = "message", method = RequestMethod.GET)
public ModelAndView messages() {
ModelAndView mav = new ModelAndView("message/list");
mav.addObject("messages", messageRepository.findAll());
return mav;
}
You should always use org.springframework.ui.Model as argument. This class is basically a Map with key/value pairs that are made available to Thymeleaf for rendering.
Your first example is how you should do it:
#GetMapping("/employees") //<1>
private String viewAllEmployees(Model model) {
model.addAttribute("employees", employeeService.getAllEmployees()); // <2>
return "employeeList"; // <3>
}
<1> This is the URL that the view will be rendered on
<2> Add any Java object you want as attribute(s) to the model
<3> Return the name of the Thymeleaf template. In a default Spring Boot with Thymeleaf application, this will refer to the template at src/main/resources/templates/employeeList.html. In that template, you will be able to access your model value with ${employees}.
I have a JPA entity with a couple of fields (the real ones are more complex). I'm receiving some data via REST (POST operation in a Spring controller) and storing it right away in the JPA entities; I want to see if there is a possibility to exclude some field(s) when the request is sent, Jackson deserializes it, and constructs the object. But at the same time I want those fields to be included when I send back (object gets serialized) the response.
#Table("key_card")
public final class KeyCard {
private String username; // Don't want this to be sent as input,
// but want to be able to send it back
// in the response
#NotBlank
private final char[] password;
}
I'm just trying not to model it twice (for the request and response) if there is a way to solve this.
You can use JSON views: http://wiki.fasterxml.com/JacksonJsonView
Class Views {
static class AlwaysInclude { }
static class OnlyOnSerialize extends AlwaysInclude { }
}
And then on your view:
#Table("key_card")
public final class KeyCard {
#JsonView(Views.OnlyOnSerialize.class)
private String username;
#JsonView(Views.AlwaysInclude.class)
#NotBlank
private final char[] password;
}
To exclude a Java object property only from Json deserialization and to include instead its value during serialization you can use an appropriate combination of #JsonIgnore and #JsonProperty annotations.
In particular you should:
annotate with #JsonIgnore the property itself
annotate with #JsonIgnore its set method
annotate with #JsonProperty its get method
Here you can find an in-depth explanation and an example: Jackson: using #JsonIgnore and #JsonProperty annotations to exclude a property only from JSON deserialization