My resource is
#GET
#Path("/items")
public MyCollection<Items> getItems()throws Exception{
//Code to return MyCollection<items>
}
My Item class is
#XmlRootElement
public class Item{
private int id;
private String name;
//Have getters and Setters.
}
And My collection class is Generic as below.
public class MyCollection<T> extends MyBaseCollection{
private java.util.Collection<T> items;
private int count;
}
When i try to generate doc using enunciate. The sample Json has only the item and count and the fields of Item class is not getting reflected.
My sample Json generated is
{
"items" : [ {
}, {
}, {
}, {
}, {
}, {
}, {
}, {
} ],
"count" : ...,
}
How to get id,name inside the Item in the generated sample Json?
Thanks.
This is a limitation that i have run into as well, there is no way to specify #TypeHint on a nested object. To support documentation, consider creating a custom collection that defines "items" as a collection of specific class instead of generic.
If you have an idea of how you would want this to work (using the generic type) I suggest submitting enhancement request to Enunciate team.
I have a similar problem where I am returning a Map and I can't #TypeHint this.
Related
Here is my API Response, here the response is coming as Map object not Json.
{
"staticResponses": [
{
"code": {
"id": "someId",
"value": "44343567"
},
"staticAttributes": [
{
"id": "SEC_GUAR",
"value": "someValue4"
},
{
"id": "FIN_BOND_TYPE",
"value": ""
},
{
"id": "SEC_ISSER_ID",
"value": "someValue5"
},
{
"id": "SEC_ISSE_CRNCY",
"value": "someValue6"
}
//Here more objects with id and value(same as above) which needs to be mapped to corresponding fields of RatingModel Pojo.
]
}
]
}
API Response to equivalent Pojo field mapping
Keys Comming In API Response Corresponding Field Name in Model
SEC_GUAR guarantor
FIN_BOND_TYPE covered
SEC_ISSER_ID issuerId
SEC_ISSE_CRNCY securityCurrency
My Pojo to which I need to mapped the data
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class RatingCompositionModel implements CompositionModel {
private List<RatingModel> ratings;
}
RatingModel.java
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class RatingModel implements CompositionModel, Serializable {
private static final long serialVersionUID = -8447345872052120852L;
private String securityCurrency;
private String covered;
private String guarantor;
private String issuerId;
//here renaming fields
}
Code that I have written to achieve the same
private CompositionModel mapResponseToObject(LinkedHashMap responseBody) {
RatingCompositionModel ratingCompositionModel = new RatingCompositionModel();
List<RatingModel> ratingModelList = new ArrayList<>();
List<LinkedHashMap> responseObjectList = (List<LinkedHashMap>) responseBody.get("staticResponses");
if( null != responseObjectList && !responseObjectList.isEmpty() ) {
responseObjectList.forEach(responseObject -> {
List<LinkedHashMap> staticAttributes = (List<LinkedHashMap>)responseObject.get("staticAttributes");
if( null != staticAttributes && !staticAttributes.isEmpty()) {
RatingModel ratingModel = new RatingModel();
staticAttributes.forEach(staticAttribute -> {
if( ((String)staticAttribute.get("id")).equals("SEC_GUAR") ) {
ratingModel.setSecurityCurrency((String)staticAttribute.get("value"));
}
// more else if here...
});
ratingModelList.add(ratingModel);
}
});
}
ratingCompositionModel.setRatings(ratingModelList);
return ratingCompositionModel;
}
So here the problem is number of if-else block that I have to used,currently I have around 50 fields which I need to extract from the API Response and need to mapped to the corresponding fields in my POJO, so with my approach I have to use 50 if-else conditions and in future, if any change in my POJO like addition of some more fields(which has a high possibility) I have to add more if-else block.
Also worth noting here I cannot change the name of the fields in API response to match it with my POJO because this is some third party API not in my control.
Here looking for more dynamic solution to avoid if-else block as well to efficiently handle any future changes.
you don't need to have if-else conditions their, just iterate through staticAttributes and store them in a Map and once that is done, you can directly map this Map object to your POJO class using ObjectMapper's convertValue api.
FinalPojo readValue = objectMapper.convertValue(collect, FinalPojo.class);
But you would need to tell Jackson that which key in the map is to be mapped to what field in your POJO. And you can use #JsonProperty annotation for that.
Below is the sample POJO class
import com.fasterxml.jackson.annotation.JsonProperty;
public class FinalPojo {
#JsonProperty("SEC_GUAR")
private String guarantor;
#JsonProperty("FIN_BOND_TYPE")
private String covered;
#JsonProperty("SEC_ISSER_ID")
private String issuerId;
#JsonProperty("SEC_ISSE_CRNCY")
private String securityCurrency;
}
you can simply annotate the fields of the class with #SerializedName annotation given by Gson library. you can find an example below. Its really conveniet to use this librart to convert to/from json.
https://www.tutorialspoint.com/what-to-use-serializedname-annotation-using-gson-in-java
I have a baseclass and three extending classes. For example:
BaseClass:
public BaseClass {
int id;
}
public SubClass extends BaseClass {
int sub1;
}
public SubClass2 extends BaseClass {
int sub2;
}
Now i want to send a json file to my spring server and the server must check if it is a SubClass-type or a SubClass2-type
#PostMapping(value = "/test", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> create(#RequestBody List<BaseClass> entry);
sending JSON:
{
"id": 1,
"sub1": 1
},
{
"id": 2,
"sub2": 2
}
I except a List of BaseClasses but try to cast them in the specific subclass. How can i do this? Following did not work.
if (abc instanceof SubClass) {
log.info("abc is instance of SubClass");
} else if (abc instanceof SubClass2) {
log.info("abc is instance of SubClass2");
}
If you will accept BaseClass Spring will map your json to be compliant with only BaseClass ignoring all the other fields. So your check for subclasses will not work at all.
The simplest solution is to accept data as plain text and after that manually try to map it to your models using GSON or something similar like this
new Gson().fromJson("{
"id": 1,
"sub1": 1
}", SubClass.class);
But it is a bad way to handle this.
Your approach need to be changed architecturally. The simplest way to do it is to introduce data field to you model like this
{
"id": 1,
"data": {
"key": "sub1",
"value": 1
},
},
public Data {
String key;
int value
}
public BaseClass {
int id;
Data data;
}
this way you will be able to check
if (abc.data.key.equals("sub1")) {
log.info("abc is sub1");
} else if (abc.data.key.equals("sub1")) {
log.info("abc is sub2");
}
This will require a bit more complex further implementation, but it will work.
Hope it helps.
my first post here. I'm working on a API and i found a trouble that i don´t know how to solve it.
I´m trying to get the remaining stock of all products in my database. I´m using Spring boot and MongoDB with the Spring Data dependency.
Here is my code:
#GetMapping("/remaining-stock")
public ResponseEntity<List<Pair<String, Integer>>> showAllStock() throws EmptyDepositException{
List<Pair<String, Integer>> allStock;
try {
allStock = depServ.showAllStock();
}catch(EmptyDepositException ex) {
allStock = null;
}
return ResponseEntity.ok(allStock);
}
When i do that GET request, this is the JSON i get:
[
{
"first": "Water",
"second": 5
},
{
"first": "Milk",
"second": 40
}
]
The values are OK but i want to rename the variables names with a better name like this:
[
{
"Product name": "Water",
"Remaining stock": 5
},
{
"Product name": "Milk",
"Remaining stock": 40
}
]
There is a way to do that?
Sorry for my english, i'm from Argentina so maybe something is not clear. I hope you can help me.
Thank you all in advance.
You can use #JsonProperty annotation which 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.
public class Product implements Serializable {
#JsonProperty("Product name")
private String first;
#JsonProperty("Remaining stock")
private long second;
// implement methods for getters and setters
}
With Pair Class, you can't do that. I suggest you to create a DTO class like below :
public class CustomPair {
#JsonProperty("Product name")
private String first;
#JsonProperty("Remaining stock")
private String second;
// standard getters and setters
}
Then your controller will be like this :
#GetMapping("/remaining-stock")
public ResponseEntity<List<CustomPair>> showAllStock() throws EmptyDepositException{
List<CustomPair> allStock;
try {
allStock = depServ.showAllStock(); // depServ.showAllStock(); should return List<CustomPair>
}catch(EmptyDepositException ex) {
allStock = null;
}
return ResponseEntity.ok(allStock);
}
I am having a JSON coming from response payload of rest API. below is structure of simplified JSON but the actual is much more complex.
{
"hardware": {
"cores": 2,
"cpu": 1,
},
"name": "machine11",
"network": [
{
"interface_name": "intf1",
"interface_ip": "1.1.1.1",
"interface_mac": "aa : aa: aa: aa: aa"
}
]
}
Now I have to write POJO class to bind the JSON structure using JAXB annotations (javax.xml.bind.annotation.*).
Can anyone help me how to write POJO class for a complex JSON structure,converting JSON to XML and then using XML schema to generate class is not helping out is there any other way?
Thanks in advance:-)
As per the above JSON structure, your Java objects will look like this:
public class OutermostClass{
private Hardware hardware;
private String name;
private Set<Network> network = new HashSet<Network>;
}
public class Hardware {
private int cores;
private int cpu;
}
public class Network {
private String interface_name;
private String interface_ip;
private String interface_mac
}
I was given json file and third party class:Dealer and interface IDealerAttributes (I can not change either of them);
(I remove package name and imports to make the code simple)
JSON file
{
"serviceURL": "com.mycompany.serviceURL",
"dealerAttributes": [
{
"language": "language0",
"dealerAttributeName": "dealerAttributeName0",
"updateDate": 0
},
{
"language": "language1",
"dealerAttributeName": "dealerAttributeName1",
"updateDate": 1
}
]
}
class Dealer {
private String serviceURL;
private List dealerAttributes;
public Dealer() {
dealerAttributes = new ArrayList();
}
//Getters and Setters...
}
public interface IDealerAttributes {
public String getLanguage();
public String getDealerAttributeName();
public long getUpdateDate();
}
once I use:
gson.fromJson(jsonObj.toString(), Dealer.class);
I will get exception from this line:
Exception unmarshalling json String into Object: com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#60e26ffd failed to deserialize json object [{"language":"language0","dealerAttributeName":"dealerAttributeName0","updateDate":0},{"language":"language1","dealerAttributeName":"dealerAttributeName1","updateDate":1}] given the type java.util.List
How can I read this json file based on Dealer.class, IDealerAttributes?
But I can add one class, let's say:
public class DealerAttributes implements IDealerAttributes {
private String language;
private String dealerAttributeName;
private long updateDate;
public DealerAttributes() {
}
//Getters and Setters...
}
Since I am new to json/gson, would you please give detailed instruction to help me out? Thanks.
[added]
Consider if there are 100 fields in Dealer class, and there are another 100 interface used/nested in Dealer. I am thinking whether anyone have experience using this way: (MyType is interface)
gson.registerTypeAdapter(MyType.class, new MyType());`
You could map it to a List of Maps and then use a BeanMapper like http://code.google.com/p/orika/ to get some more informative error messages