Spring MVC mapping #RequestBody with variables containing a dot - spring

I am doing a POST request to my Rest Contoller with the following object:
{
"relationship.name": "someting"
}
I'd like to map that to a POJO:
public class Request {
private String relationshipName;
// Getters, setter and contructor
}
How would I dot that?

Annotate your property with #JsonProperty
public class Request {
#JsonProperty("relationship.name")
private String relationshipName;
...
}
By default, the mapping will use the variable name as the key for the property. So without the annotation, it would expect relationshipName. #JsonProperty allows you to customize the key without changing the variable name.

Have u tried using #JsonProperty on relationshipName?
#JsonProperty(name), tells Jackson ObjectMapper to map the JSON property name to the annotated Java field's name.

Related

Providing default values for validation in SpringBoot

I want SpringBoot to be able to provide default values for fields that the user must enter. For example, I have something like this:
*Controller class*
#PostMapping("/test")
public ResponseEntity<> myMethod(#RequestBody #Valid MyContract contract) {}
*MyContract class*
#Valid
DataObject dataObject;
*DataObject class*
#Component
public class DataObject {
private #Value("${field1.default}") String field1Default;
private String field1
public String getField1() {
return (field1 == null ? field1Default : field1);
}
}
The DataObject class needs to be created on a per request basis. There are also other places in the code where it needs to be created on demand. So I imagine it needs to be a Prototype object. But I can't figure out how to get Spring to created it properly when it creates it for the request.
Update
I have read more about #RequstBody, e.g., https://www.javadevjournal.com/spring/spring-request-response-body/ and Should spring #RequestBody class be singleton or prototype?, which explains that the object is not a Component, but a simple POJO that gets the values from the Json request. So it seems that there is no way to inject #Values from the Spring application.properties file. Is there any other way around this? Or another suggested implementation?

How to do Spring Controller method specific serialization with Jackson?

I have two different serializers for String fields. I want to use either of them conditionally based on an annotation present on the calling Controller method. I'm looking at different ways of doing this via Jackson (eg. annotationIntrospector, JsonView etc). However, I do not see anywhere I can use method annotation during serialization. I can probably check if I can follow something similar to how Jackson implements JsonViews but haven't got to a solution yet.
Here is the use case.
// Dto
public class MyDto {
#Masked //Mask the fields with an option to avoid masking based controller method annotation.
private final String stringField;
// getters, setters.
}
// controller.
// default behavior is to serialize masked.
#ResponseBody
public MyDto getMaskedDto() {
// return dto with masked value.
return this.someService.getDto();
}
// Controller
#IgnoreMasking // Do not mask the dto if method is annotated with #IgnoreMasking.
#ResponseBody
public MyDto getDtoSkipMasking() {
// return dto without masking String field value.
return this.someService.getDto();
}
You could extend Jackon's StdSerializer and override the serialize method.
So something like this:
Create a new CustomSerializer class extending StdSerializer
Override the serialize method
In the overridden method, check for the existence of the object being serialised for the existence of your custom annotation (ie IgnoreMasking). You can do this via reflection
Do your processing
Register your custom serializer into Jackson's ObjectMapper configuration as a new SimpleModule

Spring: bind url query param to POJO

I have request like ...?abc=value and following rest implementation (Spring):
#GetMapping("/")
String getSth(Pojo pojo) {
...
}
where Pojo is
Pojo {
private String someOtherName;
//getters, setters
}
Is it possible to bind query param abc to class attribute someOtherName? I know, that if query param fits to pojo attribute, it works by default...
Does Spring support custom mappings between POJO attributes and query params?

#RequestBody is getting null values

I have created a simple REST service (POST). But when i call this service from postman #RequestBody is not receiving any values.
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
#RestController
public class Add_Policy {
#ResponseBody
#RequestMapping(value = "/Add_Policy", headers = {
"content-type=application/json" }, consumes = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
public Policy GetIPCountry( #RequestBody Policy policy) {
System.out.println("Check value: " + policy.getPolicyNumber());
return policy;
}
}
My java Bean object is like below:
public class Policy {
private String PolicyNumber;
private String Type;
private String Tenture;
private String SDate;
private String HName;
private String Age;
public String getPolicyNumber() {
return PolicyNumber;
}
public void setPolicyNumber(String policyNumber) {
PolicyNumber = policyNumber;
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public String getTenture() {
return Tenture;
}
System.out.println is printing a null as a value for PolicyNumber.
Please help me to resolve this issue.
JSON which i am passing in request body is
{
"PolicyNumber": "123",
"Type": "Test",
"Tenture": "10",
"SDate": "10-July-2016",
"HName": "Test User",
"Age": "10"
}
I have even set Content-Type to application/json in postman
Check the #RequestBody import,
wrong that will cause the problem in most cases.
import io.swagger.v3.oas.annotations.parameters.RequestBody;
to solve problem It should be
import org.springframework.web.bind.annotation.RequestBody;
Try setting the first character of the properties in your JSON to lower case. Eg.
{
"policyNumber": "123",
"type": "Test",
"tenture": "10",
"sDate": "10-July-2016",
"hName": "Test User",
"age": "10"
}
Basically, Spring uses getter and setter to set the properties of the the bean object. And it takes the property of the JSON object, matches it with the setter of the same name. eg to set the policyNumber property it tries to find a setter with the name setpolicyNumber() in your bean class and use that to set the value of your bean object.
Setter would have been missed. So, Object values do not get set.
If you are not in power to change the JSON format and still want to fix this problem, try adding
#JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
annotation before your DTO (Policy in example) class.
Java convention demands the name of variable in a POJO (attribute of a class) must to be the first character in lowercase.
You have uppercase letters in your JSON properties, which is what is causing the failure.
I had lombok in my pom, and lombok annotations on my bean. I did not properly installed lombok with my STS yet, and had similar issue, my bean was not populated.
When I removed lombok annotations, my bean was properly populated.
Seems like a combination of lomboc not properly installed on STS + lomboc annotations on my bean.
if you are using Lombok Api then there are no Getters and Setters publicly visible or available to the #ResponseBody and #RequestBody annotation.
That is why we read the JSON request with null values.
So you need to comment those #Getter, #Setter annotation to Receive JSON response and Read JSON request object and generate the same getters and setters.
Restart or Hot Load (using Spring-Boot-Devtools) server and it should work for sure.
You can still use your lombok api for other Entities or BO's.
In my case was a Lombok issue. I removed all the lombok annotations and created the constructor, setter and getter manually.
As an advise, I would also set the JSON to lowercase to follow the convention.
Use the annotation org.springframework.web.bind.annotation.RequestBody and not org.springframework.web.bind.annotation.ResponseBody
In my case, empty constructor must be defined.
public MyClass(){}
Apart from lowerCamelCasing, for me what additionally needed was applying #JsonProperty(value="your expected JSON KEY name") for each of the getter and setter methods and using this operator under the POJO/Bean/DTO class.
Sample Code:
#JsonProperty(value="policyNumber")
public void setPolicyNumber(String policyNumber) {
this.policyNumber = policyNumber;
}
Had the same issue but for my case only one field was not being set. A log on the request body object showed it was being recieved as null. deleted getters and setters for the field and autogenerated them using the IDE and all worked fine.
I highly suspect a mismatch in the getter and setter definition can also cause this
I have been having this issue too, but the best way i solve mine was checking on spaces after the first quotes in every initialization of fields in my json values
see spring PropertyNamingStrategy(UPPER_CAMEL_CASE,LOWER_CAMEL_CASE ,LOWER_CASE
etc... defalult SNAKE_CASE).
Spring will auto change http contorller class parameter by naming strategy, which may be not consistant with your request json
take SNAKE_CASE as a ex, when "myToken" in java controller class, you client should send my_token instead of myToken
If you are using Lombok you need compileOnly and annotationProcessor
In my case I missed the 2nd one. So I got all null values
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
1-Make Entity class properties start with lowercase.
2-Check for Annotations.
3-Check for Constructor--> **Entity classes should have two constructor.
4-Check for Getter and Setters.
In my case, date format was given incorrectly

Spring: #NestedConfigurationProperty List in #ConfigurationProperties

Hi I am trying to get the following configuration up and running.
#ConfigurationProperties(prefix="my")
public class Config {
#NestedConfigurationProperty
private List<ServerConfiguration> servers = new ArrayList<ServerConfiguration>();
public List<ServerConfiguration> getServers() {
return this.servers;
}
}
#ConfigurationProperties(prefix = "server")
public class ServerConfiguration {
private String name;
private String description;
}
So, I want to have multiple server configs nested in objects.
I tried setting the properties with the following properties file. I can see that the list is added up by items but the members of the server are never set (name, description)
my.servers[0].name=test
my.servers[0].server.name=test
my.servers[1].name=test
my.servers[1].server.name=test
To extend what Maciej said already.
#ConfigurationProperties should be set only on root objects (that is objects that are responsible to handle a given prefix. There is no need to annotated nested objects with it.
#NestedConfigurationProperty is only used by the meta-data generator (to indicate that a property is not a single value but something we should explore to generate additional meta-data. In the case of the List there isn't any finite amount of properties so the meta-data will have to stop at the list.
In any case you need a getter and a setter for each singular property. We don't do field binding and we require a public getter to avoid exposing unnecessary properties in the meta-data.
You need to add setters and getters to ServerConfiguration
You don't need to annotate class with nested properties with #ConfigurationProperties
There is a mismatch in names between ServerConfiguration.description and property my.servers[X].server.name=test

Resources