SpringMVC can not bind json correctly - java

There a json object to be sent to the server, which contains a field:
{"sName":"something"}
In my request model,I declare a var with the same name:
String sName;
But I got null when I receive in the Controller.
I change the field name to lower-case(sname) or add JsonProperty(value="sName") annotation,it work. So where is the problem?
Controller
public ResponseEntity<JSONObject> getComprehensiveInquiryCp(#Validated #RequestBody ComprehensiveInquiryRequestModel body) {
Map<String, Object> content;
JSONObject result = new JSONObject();
String sLicense = body.getSLicense();
...
}
ComprehensiveInquiryRequestModel
#Data
public class ComprehensiveInquiryRequestModel {
...
//#JsonProperty(value = "sLicense")
private String sLicense;
...
}

From top of my head: if you have accessors in that bean, then I think jackson prefers to use them if they exist. And/or Jackson prefers accessors for private fields. As you noticed you can alter that behaviour with Jakson configuration (for example via annotions).
Try:
1. to debug, remove accessor methods and make field public. If that works then change the field back to private and make sure accessor methods are named correctly.
Also single charater prefixes are not a good practise. They can be problematic and confusing. Prefixes in general are lazy and un-Clean Code(tm) practise.

It is important that your setters (and getters) are present and actually conform to the Java naming conventions. A json property named "myFirstName" usually requires a public setter "setMyFirstName(...)" for example. So "sName" needs "setSName()", I guess.
Sure sounds like the naming convnetion might be at fault here.

Related

Jackson naming convention issue in serialization with uncommon getter method name

New to java and spring boot.
While trying to serialize the following class,
public class ActionItems {
private String APpID;
public String getAPpID() {
return APpID;
}
public void setAPpID(String aPpID) {
APpID = aPpID;
}
// other fields
}
got the json string as
{
"appID": null,
}
Whilst, cross checking the getter name with decapitilize(), it is matching with the field name.
Introspector.decapitalize("APpID") - gives "APpID"
Is jackson using a different set of rules and methods when generating the property name from the getter method?
PS: I am aware that, variable name should begin with small case. While going through the java beans naming convention spec got this question.
I am using jackson 2.9.3v.
PS: As per the link PropertyNamingStrategy, it should have produced APpID instead of appId right?
Could someone provide some input here?
Thanks.
In Jackson, you can custom PropertyNamingStrategy, and
In absence of a registered custom strategy, default Java property
naming strategy is used, which leaves field names as is, and removes
set/get/is prefix from methods (as well as lower-cases initial
sequence of capitalized characters).
Also, you can custom a property name like:
#JsonProperty("APpID") // produce {"APpID":"s"}
public String getAPpID() {
return APpID;
}

How to JSON parse immutable object in Java + Jersey

So I am just trying out Jersey for REST services and it seems to we working out fine. I only expose get services and all of the object types that I expose with these services have an immutable object representation in Java. By default Jersey seems to use a parser (JAXB?), requiring a #XmlRootElement annotation for the class that should be parsed, zero-arg constructor and setters.
I have been using Gson with no zero-arg constructor, no setters and final on all fields with no problems at all. Is there any way to accomplish this with Jersey(i.e. the paser it is using)? I have seen solutions with adapter classes that map data from a immutable object to a mutable representation, but this seems like a lot of boilerplate(new classes, more annotations, etc.) if it can be achieved with Gson without anything added.
Note: 1) I have heard people promote using zero-arg constructor and claim that Gson should not work without it. This is not what I am interested in. 2) I really have tried googling this but my keywords might be off. In other words, humiliate me in moderation.
EDIT 1:
My webservice works if I do like this:
#XmlRootElement
public class Code{
private String code; //Silly object just used for example.
public Code(){}
//(G || S)etters
}
With this class exposing the object:
#GET
#Produces(MediaType.APPLICATION_JSON)
public Set<Code> get(#QueryParam("name") String name) { // Here I want to use a class of my own instead of String name, haven't figured out how yet.
return this.codeService.get(name);
}
If I replace the Code with the following, the webservice stops working:
public class Code{
private final String code;
#JsonCreator
public Code(#JsonProperty("code") String code) {
this.code = code;
}
//Getters omitted
}
What I want is to be able to 1) have immutable objects that can be parsed to/from json and 2) Be able to define something like #RequestBody in Spring MVC for my incoming objects.
Actually this could be pretty easy with Genson. You just need the jar and then configure the Genson feature to use constructors with arguments (if you don't want to put annotations on it).
Genson genson = new GensonBuilder().useConstructorWithArguments(true).create();
// and then register it with jersey
new ResourceConfig().register(new GensonJaxRSFeature().use(genson));
Or you can use JsonProperty on the arguments. See the User Guide for more details.

Is there a better way of obtaining an object's field getters other than java reflection api or i am misusing PropertyDescriptor's getReadMethod?

Context:
I am building an Excel document in a generic way with data i receive from a SOAP service endpoint. I receive the data as a List and i have the model (JavaBeans) for every Object i receive according to the method called.
So I set the first row of the sheet as the header from the object's fields (getDeclaredFields).
Then i go on filling up the column row by row with values from the list of objects.
The problem:
I haven't found a workable way of getting the object's field values.
I have tried using the getters with the java reflection API with something like this answer's https://stackoverflow.com/a/5503534/4807777 findGetterName , findGetter however the PropertyDescriptor's getName sometimes is a different letter case from the field name as obtained from the class's getDeclaredFields.
Let's say i overcome this by capitalizing both names, the getReadMethod stil fails - doesn't seem to find getters for the fields which use the is prefix (i.e boolean fields). I don't know if i am misusing it or it is a bug (debugging the getReadMethod appears to only work with the get prefix, even though it appears to handle the is prefix case for booleans).
Considering the fact the fields aren't accesible outside of the object's package, therefore solely through invoking getters.
Is there a better way of obtaining the object's field getters or i am missing something with the getter methods?
Update: Spring's BeanUtils seems to be better for getting the properties with it's getPropertyDescriptors is better than java Class's getDeclaredFields, when the JavaBean properties are mapped to XML elements.
This fixes the different letter cases situation. However it stil doesn't find it's readMethod when not using the get prefix.
Edited - to show an example of getReadMethod not finding the is prefixed getter, as Laszlo Lugosi requested.
A simple class:
class Test {
private String assignmentType;
private Boolean conserved;
public String getAssignmentType() {return assignmentType;}
public void setAssignmentType(String assignmentType) {this.assignmentType = assignmentType;}
public Boolean isConserved() {return conserved;}
public void setConserved(Boolean conserved) {this.conserved = conserved;}
}
Run this with the findGetter and findGetterName written in the answer linked above:
{
Test obj = new Test();
obj.setAssignmentType("someType");
obj.setConserved(true);
Field[] fields = obj.getClass().getDeclaredFields();
String fieldName;
for (int i=0;i<fields.length;i++){
fieldName = fields[i].getName();
java.lang.reflect.Method method;
Object val = null;
try {
method = obj.getClass().getMethod(findGetterName(obj.getClass(),fieldName));
val = method.invoke(obj);
}
catch (Exception e){
e.printStackTrace();
}
}
}
Edited 2
While i could simply write a getReadMethod following the convention Laszlo Lugosi highlighted i do prefer finding an API for handling accessors.
As you know only the object field name, and JavaBean has convention, you can figure out the getters easily. The rules are getUpperfieldname() and isUpperfieldname if field is boolean. And you can find out the return type as well from the object field.

How to get the name of a property as string?

I have a class Car that has a Field named trunk. How can I retrieve that name only with the property that is assigned to it and without any fixed String.
Something working like this fiction would be great:
System.out.println(new Car().getTrunk().getField().getName());
Output:
trunk
I don't want to use a fixed String to retrieve the Field and it's name because that would not refactor well. If I decide to rename from trunk to boot I want this to be handled completely by my IDE's refactoring tool.
UPDATE Car class:
public class Car{
String trunk;
// getters + setters
}
BACKGROUND:
I want to use Primefaces' Dynamic Columns for a CRUD-UI for several entities which uses a columnTemplate containig the names of the Fields/properties to be evaluated by Expression Language.
Consider introducing a enum holding all the properties (without values), for example
enum CarProperty {
TRUNK, HOOD, WHATEVER;
}
and storing them in Car as EnumMap:
class Car {
private Map<CarProperty, String> propsToValues = new EnumMap<>(...);
public String getValue(CarProperty property) { ... }
}
property name could be accessed by
((CarProperty) anyPropery).toString()
And obviously it is easy to refactor
Is not a good idea access to the property name.
With reflection you are breaking OOP principles.
getTrunk() not allways need to access a trunk property
You can have a
private Trunk trunk;//remember to change the TRUNK_FIELD
public static final TRUNK_FIELD = "trunk"
but... try to avoid this solution.

Jackson - Required property?

I'm using Jackson's readValue() method on an object mapper to read from a JSON file and convert it into my java object.
eg.
mapperObject.readValue( node, MyTargetClass.class )
Are there any annotations that I can set on MyTargetClass to enforce required attributes? For example, if I have a JSON object with properties ABC,DEF and GHI, and my Json is the following
{
"ABC" : "somevalue"
"DEF" : "someothervalue"
}
I want it to fail somehow, and only succeed on the readValue if it contained ABC, DEF and GHI.
You can mark a property as required with the #JsonProperty(required = true) annotation, and it will throw a JsonMappingException during deserialization if the property is missing or null.
Edit: I received a downvote for this without comment. I'd love to know why, since it does exactly the right thing.
Jackson does not include validation functionality, and this is by design (i.e. that is considered out-of-scope). But what is usually used is Bean Validation API implementation.
The nice thing about this is decoupling between data format handling, and validation logic.
This is what frameworks like DropWizard use; and it's the direction JAX-RS (like Jersey) are taking things for JAX-RS 2.0.
If you want to make sure a json field is provided, you have to use the #JsonProperty(value = "fieldName", required = true) annotation as a parameter to the constructor. But this is not enough, also the Constructor should have #JsonCreator annotation.
For example, if you have a field named 'endPoint' and you want o make sure it is provided in the JSON file, then the following code will throw an exception if it is not provided.
#JsonCreator
public QuerySettings(#JsonProperty(value = "endPoint", required = true) String endPoint) {
this.endPoint = endPoint;
}
I found this link helpful to understand the Jackson annotations. It also well explains why required=true is not enough and counter-intuitive to its name.
If you are neither satisfied with using #JsonProperty(required = true) as it works only with #JsonCreator nor with the use of bean validation then one more way of tackling it would be to catch this in your setter methods for the relevant variables.
You can simply check if the variable is null before setting it and throw an IllegalArgumentException or NullPointerException (as preferred by few people)
Note: It depends on how your POJO is defined too, so please make sure that it is going the setter method route for this solution to work.

Categories