I have a JAX-RS method that returns me a List with DO's. Unfortunetly when I go to the path which is mapped by the method i get only an empty json list like:
[{}, {}, {}]
My resource method looks like this:
#GET
#Produces("application/json")
public List<ModelDO> getModels() {
List<ModelDo> models = modelRepo.findAllModelsWithName("Name");
return models;
}
I'm 100% sure the objects exists and the list isn't empty, because I have checked it in the debugger.
The ModelDO class is a simple POJO:
public class ModelDO {
private int id;
private String name;
//public getters
}
What should I do to get an non empty json response?
PS. When I'm returning a single object I get the same problem -> {}
EDIT:
modelRepo:
public List<ModelDO> findAllModelsWithName(String name){
return new JPAQueryFactory(entityManager).selectFrom(modelEntity)
.where(modelEntity.name.eq(name))
.fetch();
}
ModelRepo.class is #Injected into my Resoure class
The reason was that my Model object did not have field setters, only getters.
Related
I have this custom Object called Example, that have a org.json.JSONObject as a mongo query.
public class ExampleObject {
private JSONObject query;
private String[] projections;
private Number limit;
// Constructors, getters and setters
}
I'm using a REST controller like this:
#RestController
#RequestMapping("/example")
public class ExampleRestController {
#RequestMapping(value = "/search", method = RequestMethod.POST)
#ResponseBody
public String example(#RequestBody ExampleObject example) {
return "This is an example";
}
And then, I do with Postman the following request:
POST to http://localhost:8080/example/search
with body as follows (I have checked the validity of the JSON with http://jsonlint.com):
{
"query":{
"field1":"value1",
"field2":"value2"
},
"projections":["field3, field4"],
"limit":3
}
The result is: projections and limit on object "example" have setted correctly but query is an empty JSONObject (not null). If I don't send the field query, the JSONObject variable on the object "example" is null.
I don't understand why the field query is not setted fine. I want to Spring maps the #RequestBody json to an ExampleObject.
Spring (particularly Jackson) does not know how to deserialize JSONObject. You can use com.fasterxml.jackson.core.JsonNode instead.
I'm a litte bit lost, I have to admit. I wrote a Spring Boot (1.3M2) application that receives a JSON object which it needs to store in a database:
#RequestMapping(value = "/fav", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<String> setFavorite(#RequestBody List<Favorite> favorites) {
...
internally this method passes the JSON to another method which stores it line by line in a database:
jdbcTemplate.batchUpdate(INSERT_FAVORITE, new BatchPreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Favorit fav = favorites.get(i);
ps.setString( ...
}
#Override
public int getBatchSize() {
int size = favorites.size();
return size;
}
When I POST a JSON to the controller which does not match the structure of my Favorite-object I only see null values in my database. Obviously Jackson tries its best to convert my JSON into a Java object but fails and sets all values of the object it finds no value for to null.
Then this list of sort of empty objects is written to the database.
I use curl to POST the values
curl -vX POST https://localhost/fav -d #incorrectype.json
This can't be the source of error because it works with a favorite.json. How can I have my controller / Jackson detect if I use a JSON that does not match ?
One solution is to use annotations from javax.validation, and instead of accepting a List in the controller signature, use a custom wrapper along the lines of this (getters/setters omitted):
public class FavoriteList {
#Valid
#NotNull
#Size(min = 1)
private List<Favorite> favorites;
}
then for the Favorite class add the validation as needed, e. g.:
public class Favorite {
#NotNull
private String id;
}
with these changes in place, modify the controller method signature along these lines:
public ResponseEntity<String> setFavorite(#Valid #RequestBody FavoriteList favoritesList) {
This way, input failing validation will throw exceptions before anything in the controller method is executed.
I am using JAX-RS (CXF) with JaxB and Jackson to provide a REST-API.
Unfortunately, none of the found results helps me with following (simple) problem:
I implemented following method:
#POST
#Path(ApiStatics.ARMY_CREATE_ARMY)
public com.empires.web.dto.Army createArmy(#FormParam("locationid") long locationId, #FormParam("name") String name, #FormParam("troops") ArmyTroops troops) {
and here are is my model class:
#XmlRootElement
#XmlSeeAlso(ArmyTroop.class)
public class ArmyTroops {
public ArmyTroops() {
}
public ArmyTroops(List<ArmyTroop> troops) {
this.troops = troops;
}
#XmlElement(name = "troops")
private List<ArmyTroop> troops = new ArrayList<ArmyTroop>();
public List<ArmyTroop> getTroops() {
return troops;
}
public void setTroops(List<ArmyTroop> troops) {
this.troops = troops;
}
}
ArmyTroop
#XmlRootElement(name = "troops")
public class ArmyTroop {
#XmlElement
private long troopId;
#XmlElement
private String amount;
public long getTroopId() {
return troopId;
}
public void setTroopId(long troopId) {
this.troopId = troopId;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
}
My json that i send looks like this:
locationid 1
name asdasd
troops {"troops":[{"troopId":4,"amount":"5"},{"troopId":6,"amount":"5"}]}
Unfortunately, the object gets not transformed. Instead I receive this error:
InjectionUtils #reportServerError - Parameter Class com.empires.web.dto.in.ArmyTroops has no constructor with single String parameter, static valueOf(String) or fromString(String) methods
If I provide the constructor with a single string parameter, I get passed the whole json string for "troops" as mentioned above.
Any ideas why JaxB does not work at this point?
You are passing all your parameters with #Form annotation.
But the Form part of the http message must be an xml data structure.
Your 3 parameters don't have a main xml datastructure so it wont work.
In short, form params are send as body.
Cxf use the MultivaluedMap to send params (cxf have an xml model for this structure).
As you can see it is not fit for parameters that can't be trivally serialized.
Here me solution would be to drop the #FormParam to avoid the problem:
1) Use #PathParam #CookieParam to send yours first 2 parameters, and the 'no tag' (body) only for the army compositions.
2) Define an uber object that take all parameters and can be serialized as xml datastructure and use the 'no tag' (body) sending.
3) Use soap, with cxf it is really easy to gets both Rest and Soap.
I have some JSON in the following format that I'm trying to parse with Jackson -
"response":{
"response_inner":{
"a":{"field1":2,"field2":0,"field3":5,"field4":0,"field5":[{"field5_1":"b","field5_2":1},{"field5_1":"c","field5_2":1}]},
"d":{"field1":2,"field2":6,"field3":11,"field4":0,"field5":[{"field5_1":"c","field5_2":1},{"field5_1":"b","field5_2":1}]},
"response_inner_bool":false
}
}
Here "a", "b" etc. are some Strings that can change in each response.
I've created a Java object to represent the 'response_inner' (let's call it ResponseInner) and another to represent the object containing the field?s (let's call this one FieldInfo) but I'm not sure how to parse this using the #JsonCreator and #JsonProperty annotations - ResponseInner objects can contain any number of String -> FieldInfo mappings.
I tried parsing it like this -
public class Response {
private ResponseInner responseInner;
#JsonCreator
public Response(#JsonProperty("response_inner") ResponseInner responseInner) {
this.reponseInner = responseInner;
}
}
public class ResponseInner {
private Map<String, FieldInfo> stringToFieldInfoMap;
private boolean responseInnerBool;
#JsonCreator
public ResponseInner(Map<String, FieldInfo> stringToFieldInfoMap, #JsonProperty("response_inner_bool") boolean responseInnerBool ) {
this.stringToFieldInfoMap = stringToFieldInfoMap;
this.responseInnerBool = responseInnerBool;
}
}
But it complains that Argument #0 of constructor has no property name annotation; must have name when multiple-paramater constructor annotated as Creator. Any suggestions for how to get around this?
You don't seem to be using the stringToFieldInfoMap within ResponseInner anyway. Why do you need to pass it as parameter?
If you do need it in that class, you can simply set it via a setter rather than passing it to constructor.
Alternatively, you could perhaps utilize a third class which deals with that actual mapping of the response, which consumes the Response object (which would in turn consume the ResponseInner object which has had the Map removed from it). This would actually allow you to decouple the mapping logic from the response logic perhaps.
public class MappedResponse {
private Map<String, FieldInfo> stringToFieldInfoMap;
private Response response;
public MappedResponse(Map<String, FieldInfo> stringToFieldInfoMap, Response response) {
this.stringToFieldInfoMap = stringToFieldInfoMap;
this.response = response;
}
}
I am having a deserialization problem using the GSON library.
The following is the JSON code which I try to deserialize
{"response": {
"#service": "CreateUser",
"#response-code": "100",
"#timestamp": "2010-11-27T15:52:43-08:00",
"#version": "1.0",
"error-message": "",
"responseData": {
"user-guid": "023804207971199"
}
}}
I create the following classes
public class GsonContainer {
private GsonResponse mResponse;
public GsonContainer() { }
//get & set methods
}
public class GsonResponse {
private String mService;
private String mResponseCode;
private String mTimeStamp;
private String mVersion;
private String mErrorMessage;
private GsonResponseCreateUser mResponseData;
public GsonResponse(){
}
//gets and sets method
}
public class GsonResponseCreateUser {
private String mUserGuid;
public GsonResponseCreateUser(){
}
//get and set methods
}
After calling the GSON library the data is null. Any ideas what is wrong with the classes?
Thx in advance for your help ... I assume it's something trivial ....
#user523392 said:
the member variables have to match exactly what is given in the JSON response
This is not the case.
There are a few options for specifying how Java field names map to JSON element names.
One solution that would work for the case in the original question above is to annotate the Java class members with the #SerializedName to very explicitly declare what JSON element name it maps to.
// output: [MyObject: element=value1, elementTwo=value2]
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
public class Foo
{
static String jsonInput =
"{" +
"\"element\":\"value1\"," +
"\"#element-two\":\"value2\"" +
"}";
public static void main(String[] args)
{
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
MyObject object = gson.fromJson(jsonInput, MyObject.class);
System.out.println(object);
}
}
class MyObject
{
String element;
#SerializedName("#element-two")
String elementTwo;
#Override
public String toString()
{
return String.format(
"[MyObject: element=%s, elementTwo=%s]",
element, elementTwo);
}
}
Another approach is to create a custom FieldNamingStrategy to specify how Java member names are translated to JSON element names. This example would apply the same name mapping to all Java member names. This approach would not work for the original example above, because not all of the JSON element names follow the same naming pattern -- they don't all start with '#' and some use camel case naming instead of separating name parts with '-'. An instance of this FieldNamingStrategy would be used when building the Gson instance (gsonBuilder.setFieldNamingStrategy(new MyFieldNamingStrategy());).
class MyFieldNamingStrategy implements FieldNamingStrategy
{
// Translates the field name into its JSON field name representation.
#Override
public String translateName(Field field)
{
String name = field.getName();
StringBuilder translation = new StringBuilder();
translation.append('#');
for (int i = 0, length = name.length(); i < length; i++)
{
char c = name.charAt(i);
if (Character.isUpperCase(c))
{
translation.append('-');
c = Character.toLowerCase(c);
}
translation.append(c);
}
return translation.toString();
}
}
Another approach to manage how Java field names map to JSON element names is to specify a FieldNamingPolicy when building the Gson instance, e.g., gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);. This also would not work with the original example, however, since it applies the same name mapping policy to all situations.
The JSON response above cannot be deserialized by GSON because of the special characters # and -. GSON is based on reflections and the member variables have to match exactly what is given in the JSON response.