I have a complex Employee POJO class which has Name, id, salary, dept and Address(vector type) fields.I have generated the json using the jersey restful web service. But the output json does not include the certain pojo fields like address which has datatype as vector. All the fields in POJO class has getter and setters.
Any specific reason that why certain fields are not part of generated JSON ?
//Used below code to generate the JSON
#Path("/employeedDetails")
#GET
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public EmployeedBean getDetails(#QueryParam("Id") String Id,
#Context HttpServletRequest servletRequest) {
Employee e1 = new Employee();
// Sets all Name, id, salary, dept and Address
return e1;
}
You are missing code. Can you post what you are returning? If you are returning an array (such as a Java List object), you'll want to wrap that inside another POJO class. I was having the same issue (see RESTful POJO -> JSON mapping not picking up new fields) and this was what was causing it, since the returned JSON was starting with brackets [] instead of {} and therefore JavaScript wasn't parsing it properly. Returning a single object instead of a List fixed the issue.
Related
I need to consume a REST endpoint using spring RestTemplate. Below is the sample response from the endpoint and I need to fetch nested employee json and map it to model object. I found various complex solutions like
Deserializing response to a wrapper object and then fetching Employee object from it
Getting the response as a string and then converting it to json and deserializing
None of these solutions are simple and clean. Not sure if there is a clean and automatic way of doing it like this
ResponseEntity<Employee> response = restTemplate.exchange(URL,..?..);
Response -
{
"employee": {
"id": "123",
"first_name": "foo",
"last_name": "bar"
},
"session": {
"id": "1212121",
"createdDate": "2022-08-18T19:35:30Z"
}
}
Model object -
public class Employee {
private long emplId;
private String fName;
private String lName;
}
RestTemplate can do all of this for you, but first, your object doesn't match your response.
Ideally, you would have a Class that has an Employee and Session, like this
public class HaveSomeClassMan {
private Employee employee;
private Session session;
}
Then you can do
HaveSomeClassMan haveSomeClassMan = restTemplate.postForObject("URL", "requestObject", HaveSomeClassMan.class);
But, since you already have a JSON string, here's how you can convert it to a JSONObject, get the Employee out of it, and use the ObjectMapper to convert it to an Employee object.
JSONObject jsonObject = new JSONObject(s); // where s is your json string
String theEmployee = jsonObject.get("employee").toString(); // get the "employee" json from the JSONObject
Employee employee = new ObjectMapper().readValue(theEmployee, Employee.class); // Use the object mapper to convert it to an Employee
You do need to pay attention, though, as your model doesn't line up with your json. Your model calls the first name field, fname, yet your json has this as first_name. These properties all need to line up. If you want to keep your model as you've defined it, you need to annotate your fields with what their corresponding json field is, like this:
#JsonProperty("first_name")
private String fName;
This tells the mapper to map the JSON field first_name to the property fName. Regardless of whether you let RestTemplate do the mapping for you or you do it manually via the JSONObject approach, your model needs to match your JSON string. You can do this implicitly just by naming the fields in your model the same as they are in your JSON, or explicitly by adding the #JsonProperty to each field that doesn't implicitly map.
I am new to Spring Rest. While Doing POST, we have 2 options either #RequestBody or #RequestParams.
My query is not what they are. I am pretty well know what they are.
Normally we use #RequestParams for form-urlencoded and #RequestBody for JSON/XML.
I have a scenario as below:
class EmployeeDTO {
long id;
String name;
String age;
String address;
String salary;
//Getters and Setters
}
For POST, I can directly use as void doSomething(#RequestBody EmployeeDTO){ }
and also I can do same thing but using 5 RequestParams
void doSomething(#RequestParam(id) long id, #RequestParam(name) String name, #RequestParam(age) String age, #RequestParam(address) String address, #RequestParam(salary) String salary){ }
I have seen some good sites like Stripe, they following only #RequestParam in their REST Api.
I actually got to understand that we use RequestBody for Complex Input and#RequestParam for simple parameters.
So, my actual query is: In above class, had only 5 parameters, I am thinking its okay going with #RequestParam, But what if there are like 7 or 10 input params, then should I chose RequestBody or (7 or 10) REquestParam?
EDIT:
class Orders {
String id;
Employee employee;
}
It is not really a choice based on "number of data I have to push on server".
Historically and in general the use of the query string is, as the name implies, to query data. And so request param would be the preferred choice when you want to "pull" data HTTP GET
Here if the goal is to "push" data on the server (for instance "to create an employee") you should prefer sending this data in request body.
Moreover the query string is part of the URL, and it can be read by everyone sitting between the clients and the API, so we shouldn’t put sensitive data like passwords into the query string.
you can mimic the format of query string in your body by using the mime type application/x-www-form-urlencoded. Here request body uses the same format as the query string.
parameter=value¶meter2=another
I am trying to Map a JSON response to a Java POJO which has a different field name from different API.
I need an efficient way to do this reducing boilerplate codes.
I have tried mapping the JSON property field in Java POJO.
However, the problem is I am fetching data from different sources.
Let's say I have below user class
Class User{
String name;
String contact;
}
The JSON I may receive from different sources can be
{"name": "ABC" , "contact": "123456"}
or
{"userName": "XYZ" , "mobileNo":"4354665"}
There may be more variations as we go on integrating more API's
Is there a way I can archive this?
above is just a simple example
there could be more complex JSON object I may need to read.
like List of User etc.
You can use the #JsonAlias() to give the variable more than one JSON key binding.
#JsonAlias is introduced in Jackson 2.9 release. #JsonAlias defines one or more alternative names for a property to be accepted during deserialization i.e. setting JSON data to Java object. But at the time of serialization i.e. while getting JSON from Java object, only actual logical property name is used and not alias. #JsonAlias is defined as follows.
#Entity
Class User{
#JsonProperty()
#JsonAlias({"name", "userName"})
String name;
#JsonProperty()
#JsonAlias({"contact", "mobileNo"})
String contact;
}
You could use the #JsonSetter annotation like :
public class User{
public String contact;
public String name;
#JsonSetter("name")
public void setName(String name) {
this.name = name;
}
#JsonSetter("userName")
public void setName(String name) {
this.name = name;
}
}
Instead of directly mapping to an entity class , you should have a DTO object or model in between to map the json response. Then, you can convert that into any entity you may choose.If you are fetching the data from different sources , it means you are calling different endpoints, why don't you create different DTO 's for that.In that way even if one of the endpoints introduce a change , it won't affect the rest of the endpoint calls.
Vice-versa you could have different DTO objects being returned from the two endpoints instead of returning the same Entity class as well, that way you can have control over which attributes should be there in the response.
To reduce the boiler plate code, you could use library such as MAP STRUCT to enable conversion between entity and DTO objects easily
Read here about the advantages of using a DTO .
I have a User entity that has as many properties as there are columns in the database and a transient one next to that. The user can be part of an Organisation, which is a onetoone relationship. In that entity the data type is an Organisation object.
The model is also used in the controller to check and contain the request data values, but this cannot be achieved with organisation, because the user passes the name as a string and in the entity, the organisation is an object as already mentioned.
So I would like to add another property that can contain the organisation name, so then I can convert it to an Organisation object in the Service. But I can't add a regular property because Spring JPA will think it should be a column and it can't be a transient property either, because it's ignored on the controller side for the request.
Currently I'm achieving this by adding another parameter with #RequestParam(name="organisationname"), and passing it together with the User object to the Service, but I have the feeling that this is not the proper way.
How can I approach this differently and in the User entity itself?
You can have your JSON serializer NOT ignore #Transient fields (I like this approach as transient is a DB term so it shouldn't be affecting your JSON serialization) - you can then use #JsonIgnore to skip JSON serialization properties.
So #Transient to ignore when interacting with the DB, #JsonIgnore to ignore when serializing/deserializing.
If using the Jackson ObjectMapper you can do the following:
#Bean
public ObjectMapper objectMapper() {
final ObjectMapper mapper = new ObjectMapper();
final Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
mapper.registerModule(hibernate5Module);
return mapper;
}
How do I obscure the values of fields used in url strings in a spring mvc web app?
For example, if I want to send the record with recordID=1 into the view, I give the user a hyperlink with the following url:
https://myapp.com/urlpattern?recordID=1
As you can see, this not only exposes the recordID=1, it also tempts a malicious user to start typing other numbers to mine other records such as recordID=5 or recordID=9.
Does the spring framework or spring security have a built-in way of encrypting url strings? Or do I need to change the id values in the underlying database using hibernate?
The controller code for the above url pattern is:
#RequestMapping(value = "/urlpattern", method = RequestMethod.GET)
public String processUrlPattern(#RequestParam("recordID") String recordId,
HttpServletRequest request, BindingResult result, Map<String, Object> model) {
Long recId = Long.valueOf(recordId).longValue();
RecordObject sel_record = this.appService.findRecordById(recId);
model.put("sel_record", sel_record);
return "foldername/jspname";
}
Note that all entities in the app inherit from the same BaseEntity whose id-generating code is as follows:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'BaseEntity' ELSE dtype END)")
#org.hibernate.annotations.DiscriminatorOptions(force=true)
public abstract class BaseEntity {
#Transient
private String dtype = this.getClass().getSimpleName();
#Id
#GeneratedValue(strategy=GenerationType.TABLE, generator="TBL_GEN")
#TableGenerator(
name="TBL_GEN",
table="GENERATOR_TABLE",
pkColumnName = "mykey",
valueColumnName = "hi",
pkColumnValue="id",
allocationSize=20
)
protected Integer id;
//other stuff
}
NOTE: All the users are authenticated/authorized using Spring security. However, the data is very sensitive, and it is important that no one be able to manipulate url strings.
Use HDIV, it does this out of the box:
http://hdiv.org/hdiv-documentation-single/doc.html
"A6 (Sensitive data exposure) : HDIV offers a confidentially property to all data generated at sever side. That is to say, HDIV replace original parameter values generated at server side by relative values (0,1,2,4, etc.) that avoid exposing critical data to the client side."