I have some Json in the following form:
"items": [
{
"id": 1,
"text": "As a user without a subscription, I get a choice of available ones.",
"status": "finished",
"tags": [
{
"id": 1234,
"name": "feature=subs"
},
{
"id": 1235,
"name": "epic=premium"
}
]
},
{
"id": 2,
...
There are more fields but I have ommitted them for clarity.
I am trying to map each story to a Story Class with fields ID, Text, Status and a list of Tags. I've got it working fine using the following:
public Project JsonToProject(byte[] json) throws JsonParseException, JsonMappingException, IOException
{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode rootNode = mapper.readValue(json, JsonNode.class);
int storyCount = rootNode.get("totalItems").asInt();
ArrayNode itemsNode = (ArrayNode) rootNode.get("items");
Project project = new Project();
for (int i = 0; i < storyCount; i++)
{
Story story = JsonToStory(rootNode.get(i));
project.addStory(story);
}
return project;
}
Where a project is simple an ArrayList of Stories, and JsonToStory is the following method:
public Story JsonToStory(JsonNode rootNode) throws JsonParseException, JsonMappingException, IOException
{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Story story = mapper.readValue(rootNode, Story.class);
return story;
}
The Story Class is as follows:
public class Story {
private int id;
private String text = new String();
private String status = new String();
private final List<Tag> tags = new ArrayList<Tag>();
public void setId(int i)
{
id = i;
}
public void setText(String s)
{
text = s;
}
public void setStatus(String s)
{
status = s;
}
public void setTags(Tag[])
{
???
}
}
with the get methods and print methods. The Tag Class simply contains two string fields.
I don't know how to structure the setTags method, in order to result in an arraylist of Tag objects, and haven't been able to find anything to help.
Thanks!
You have marked your tags as final, which will probably block the setter from setting the tags. You can try this:
public class Story {
private int id;
private String text = new String();
private String status = new String();
private List<Tag> tags;
public void setTags(List<Tag> tags){
this.tags = tags;
}
OR
public class Story {
private int id;
private String text = new String();
private String status = new String();
private Tag[] tags;
public void setTags(Tag[] tags){
this.tags = tags;
}
Related
I am struggling to deserialise complex nested Json data into Java objects I think my class structure is wrong. Here is my Json data:
{
"resultsPerPage": 20,
"startIndex": 0,
"totalResults": 2,
"result": {
"dataType": "CPE",
"feedVersion": "1.0",
"cpeCount": 2,
"feedTimestamp": "2021-03-19T13:06",
"cpes": [
{
"deprecated": false,
"cpe23Uri": "cpe:2.3:o:microsoft:windows_10:1511:*:*:*:*:*:x64:*",
"lastModifiedDate": "2015-12-09T17:28Z",
"titles": [
{
"title": "Microsoft Windows 10 1511 64-bit",
"lang": "en_US"
}
],
"refs": [
{
"ref": "https://www.microsoft.com/en-us/",
"type": "Vendor"
}
],
"deprecatedBy": [],
"vulnerabilities": [
"CVE-2016-0174",
"CVE-2016-0171"
]
}
Here is the class I map the Json data to:
public class RESPONSE {
Result result;
}
class Result {
List<Cpes> cpes;
}
class Cpes {
String cpe23Uri;
List<Titles> titles;
List<String> vulnerabilities;
}
class Titles{
String title;
}
When I debug my code r in the below code is null and I think it's because my RESPONSE class isn't set up right.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
RESPONSE r = mapper.readValue(response.getContent(), RESPONSE.class);
System.out.println(r);
Your object model should match the structure of the JSON you are trying to read. For example, it'll have to look something like the following:
public class Response {
private int resultsPerPage;
private int startIndex;
private int totalResults;
private Result result;
// Should include getters and setters
}
public class Result {
private String dataType;
private String feedVersion;
private int cpeCount;
private String feedTimestamp;
private CPE[] cpes;
// Should include getters and setters
}
public class CPE {
private boolean deprecated;
private String cpe23Uri;
private String lastModifiedDate;
private Title[] titles;
private Ref[] refs;
private String[] deprecatedBy;
private String[] vulnerabilities;
// Should include getters and setters
}
public class Title {
private String title;
private String lang;
// Should include getters and setters
}
public class Ref {
private String ref;
private String type;
// Should include getters and setters
}
Note that to keep the code sample short, I've omitted the getters and setters.
Edit: As Tugrul pointed out below, since fail on unknown property is disabled, it won't fail if there are missing fields in your model. The only issue is the missing getters and setters.
I also found another way to solve this issue for future reference.
I used a tree data structure to access my Json fields which means I can just declare a flat class:
public class Test {
private String cpe23Uri;
private String title;
private List<String> vulnerabilities;
public String getCpe23Uri() {
return cpe23Uri;
}
public void setCpe23Uri(String cpe23Uri) {
this.cpe23Uri = cpe23Uri;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getVulnerabilities() {
return vulnerabilities;
}
public void setVulnerabilities(List<String> vulnerabilities) {
this.vulnerabilities = vulnerabilities;
}
}
I then mapped using a Tree
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode resultNode = mapper.readTree(response.getContent());
Test t = new Test();
t.setCpe23Uri(resultNode.get("result").get("cpes").get(0).get("cpe23Uri").textValue());
is there a way using java 8 feature to convert multiple eums data to single pojo and return it as list.
I am trying this because i have scenario in application to return thedrop down values from enums from backend.
public enum TransactionTypeStatuses {
NEW("NEW"),
ACTIVE("ACTV"),
String code;
TransactionTypeStatuses(String code) {
this.code = code;
}
public String code() {
return code;
}
}
public enum MemberTypes {
CENTRAL_BANK("MB01"),
DIRECT_PARTICIPANT("MB02");
private String code;
private MemberTypes(String code) {
this.code =code;
}
public String getCode() {
return code;
}
}
public class EnumDataPojo {
private String id;
private String description;
//setters and getters
}
Add the enums data to the pojo and convert the pojo to the json response
public class Application {
public static void main(String[] args) throws JsonProcessingException {
List<EnumDataPojo> response = convertEnumsToPojo(); //contains the data of All enums in "id" and "desscription" format
ObjectMapper mapper = new ObjectMapper();
String response = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(data);
System.out.println(response);
}
stiatic List<EnumDataPojo> convertEnumsToPojo(){
List<EnumDataPojo> dataList = new ArrayList<>();
for(TransactionTypeStatuses enum1: TransactionTypeStatuses.values())
{
EnumDataPojo data1 = new EnumDataPojo ();
data1.setID(enum1.getCode());
data1.setdescription(String.value(enum1));
dataList.add(data1);
}
for(MemberTypes enum2: MemberTypes.values())
{
EnumDataPojo data2 = new EnumDataPojo ();
data2.setID(enum2.getCode());
data2.setdescription(String.value(enum2));
dataList.add(data2);
}
return dataList;
}
}
json response from the above code
{
"transactionTypeStatuses":[ //enum
{
"id":"NEW",
"description":"New"
},
{
"id":"ACTV",
"description":"active"
}
],
"memberTypes":[ //enum
{ "id": "MB01", "description": "Central Bank" },
{ "id": "MB02", "description": "Direct Participant" }
]
}
Updated answer
public class EnumDataValues{
private String id;
private String description;
//getters and setters
}
//convert each enum to pojo and put it in list.
private List<EnumDataValues> getEnumReferenceData(Class<?> c) {
List<EnumDataValues> referenceDataList = new ArrayList<>();
List enumConstants = Arrays.asList(c.getEnumConstants());
if (!enumConstants.isEmpty()) {
enumConstants.forEach(t -> {
EnumDataValues referenceData = new EnumDataValues();
referenceData.setId(String.valueOf(String.valueOf(t)));
referenceData.setDescription(String.valueOf(t));
referenceDataList.add(referenceData);
});
}
return referenceDataList;
}
I don't think your code will give you correct response. You should add data in loop to get all values of each enums
List<EnumDataValues> enum1DataList = new ArrayList<>();
for(Enum1 enum1: enum1.values()){
EnumDataValues data1 = new EnumDataValues ();
data1.setID(enum1.getCode());
data1.setdescription(String.value(enum1));
dataList.add(data1);
}
Do same for other enums
Update:
Use Map<String, List<EnumDataValues>> as response type and set the enum data.
Map<String, List<EnumDataValues>> convertEnumsToPojo(){
List<EnumDataPojo> dataList = new ArrayList<>();
for(TransactionTypeStatuses enum1: TransactionTypeStatuses.values())
{
EnumDataPojo data1 = new EnumDataPojo ();
data1.setID(enum1.getCode());
data1.setdescription(String.value(enum1));
dataList.add(data1);
}
List<EnumDataPojo> dataList2 = new ArrayList<>();
for(MemberTypes enum2: MemberTypes.values())
{
EnumDataPojo data2 = new EnumDataPojo ();
data2.setID(enum2.getCode());
data2.setdescription(String.value(enum2));
dataList2.add(data2);
}
Map<String, List<EnumDataValues>> map = new HashMap<>();
map.put("transactionTypeStatuses", enum1DataList);
map.put("memberTypes", enum2DataList);
return map;
}
I'm using only jersey and not jackson to create a REST api. I've two model objects,
public class Course {
private int id;
private String name;
private Teacher teacher;
}
public class Teacher {
private int id;
private String givenName;
private String familyName;
}
I'm creating a service and returning a List of Course objects,
public List<Course> getAll(){
return db.getCourseList();
}
The display is as expected,
[{"id":101,"name":"Introduction to Java","teacher":{"familyName":"Bar","givenName":"Foo","id":201}},{"id":102,"name":"Intermediate Java","teacher":{"familyName":"Prank","givenName":"Foo","id":202}}]
Now I want to customize my JSON object to display in the following format, with only the teacher ID.
[{"id":"100","name":"Introduction to Java","teacherId":"201"},{"id":"101","name":"Intermediate Java","teacherId":"201"}
So this is the view model that I designed.
#XmlRootElement
public class CourseTeacherIdView {
private int id;
private String name;
private int teacherId;
CourseTeacherIdView(){
}
public CourseTeacherIdView(int id, String name, int teacherId){
this.id = id;
this.name = name;
this.teacherId = teacherId;
}
}
And I use this method to return the List of view objects.
public List<CourseTeacherIdView> getAll(){
List<Course> list = db.getCourseList();
List<CourseTeacherIdView> viewList = new ArrayList<>();
for(Iterator<Course> itr = list.iterator(); itr.hasNext();){
Course c = (Course) itr.next();
viewList.add(new CourseTeacherIdView(c.getId(), c.getName(), c.getTeacher().getId()));
}
return viewList;
}
This is the result that I get.
[{},{},{}]
What am I doing wrong.
You can achieve that with Jackson and creating a custom serializer like the following:
public class CourseSerializer extends JsonSerializer<Course> {
#Override
public void serialize(Course value,
JsonGenerator gen,
SerializerProvider serializers) throws IOException {
gen.writeStartObject();
Field[] fields = value.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
Object obj = field.get(value);
if (obj instanceof Teacher) {
Teacher teacher = (Teacher) obj;
gen.writeStringField("teacherId", String.valueOf(teacher.getId()));
} else {
gen.writeStringField(field.getName(), obj.toString());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
gen.writeEndObject();
}
}
Test case:
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Course.class, new CourseSerializer());
mapper.registerModule(module);
Teacher teacher1 = new Teacher(123, "teacher1", "surename1");
Teacher teacher2 = new Teacher(234, "teacher2", "surename2");
Course course1 = new Course(1, "course1", teacher1);
Course course2 = new Course(2, "course2", teacher2);
List<Course> courses = Arrays.asList(new Course[]{course1, course2});
String serialized = mapper.writeValueAsString(courses);
}
Output:
[{
"id": "1",
"name": "course1",
"teacherId": "123"
}, {
"id": "2",
"name": "course2",
"teacherId": "234"
}]
If I understood you correctly you could either create new view model representation with only the id and map each object in the list to it, or use #jsonignore on not relevant fields (if jersey is using Jackson). Or even retrieve only the ids from the db. Depends on use case.
I am using Gson to get convert the object to json string, and its working fine but when I am sending that json to a webservice method using post, I have to add the post method's parameter name in the string.
Example:
jsonString I get from Gson new Gson().toJson(requestDataDTO) :
{
"req": {
"AppId": "2",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
},
"req1": {
"AppId": "-33",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
}
}
jsonString I want :
{
"requestDataDTO": {
"req": {
"AppId": "2",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
},
"req1": {
"AppId": "-33",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
}
}
}
for now I am adding this "requestDataDTO" string at the start of json string I got from Gson.
is there a way to achieve this ?
Assuming you have an object which looks somehow like this:
package com.dominikangerer.q25077756;
import com.google.gson.annotations.SerializedName;
public class RequestDataDTO {
// {"AppId":"2","ThirdParty":"3","UserId":"1","UserToken":"4"}
#SerializedName("AppId")
private String appId;
#SerializedName("ThirdParty")
private String thirdParty;
#SerializedName("UserId")
private String userId;
#SerializedName("UserToken")
private String userToken;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getThirdParty() {
return thirdParty;
}
public void setThirdParty(String thirdParty) {
this.thirdParty = thirdParty;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserToken() {
return userToken;
}
public void setUserToken(String userToken) {
this.userToken = userToken;
}
}
The easiest and also for me most readable solution would be to create an wrapper/container Class which contains a HashMap (key/value) like this:
package com.dominikangerer.q25077756;
import java.util.HashMap;
public class RequestDataDTOContainer {
private HashMap<String, RequestDataDTO> requestDataDTO = new HashMap<String, RequestDataDTO>();
public HashMap<String, RequestDataDTO> getRequestDataDTO() {
return requestDataDTO;
}
public void setRequestDataDTO(HashMap<String, RequestDataDTO> requestDataDTO) {
this.requestDataDTO = requestDataDTO;
}
public void putRequestDataDTO(String key, RequestDataDTO value){
this.requestDataDTO.put(key, value);
}
}
To run it simply test it with a main like this:
// enable pretty printing
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// too lazy to fill the objects by hand
String reqJson = "{\"AppId\":\"2\",\"ThirdParty\":\"3\",\"UserId\":\"1\",\"UserToken\":\"4\"}";
String req1Json = "{\"AppId\":\"-33\",\"ThirdParty\":\"3\",\"UserId\":\"1\",\"UserToken\":\"4\"}";
// deserialize it with gson
RequestDataDTO req = gson.fromJson(reqJson, RequestDataDTO.class);
RequestDataDTO req1 = gson.fromJson(req1Json, RequestDataDTO.class);
// initiliaze the container
RequestDataDTOContainer container = new RequestDataDTOContainer();
// adding the 2 req objects with the certain key
container.putRequestDataDTO("req", req);
container.putRequestDataDTO("req1", req1);
// Print it as pretty json
System.out.println(gson.toJson(container));
You are now more flexibility if you want to add more meta information like a whole meta object or similar without adding a hardcoded String to that json.
You can find the whole Example in this github repository: Java Stackoverflow Answers by DominikAngerer
Well I've been trying for like 3 hours now. Using lots of apis it still doesn't work.
I'm trying to parse
{
"id": 8029390,
"uid": "fdABNhroHsr0",
"user": {
"username": "Skrillex",
"permalink": "skrillex"
},
"uri": "/skrillex/cat-rats",
"duration": 305042,
"token": "VgA2a",
"name": "cat-rats",
"title": "CAT RATS",
"commentable": true,
"revealComments": true,
"commentUri": "/skrillex/cat-rats/comments/",
"streamUrl": "http://media.soundcloud.com/stream/fdABNhroHsr0?stream_token=VgA2a",
"waveformUrl": "http://w1.sndcdn.com/fdABNhroHsr0_m.png",
"propertiesUri": "/skrillex/cat-rats/properties/",
"statusUri": "/transcodings/fdABNhroHsr0",
"replacingUid": null,
"preprocessingReady": null
}
in to an array/list.
Any help?
I'm using Jackson from http://codehaus.org/ and so far it has lived up to all my needs.
You don't quite deal with json as raw strings in an arraylist, but rather as POJOs, here's a quick example with a subset of your json.
public class JacksonExample {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
String text = "{ \"id\": 8029390, \"user\": { \"username\": \"Skrillex\" } }";
ObjectMapper mapper = new ObjectMapper();
Pojo pojo = mapper.readValue(text, Pojo.class);
System.out.println(pojo.id);
System.out.println(pojo.user.username);
}
}
class Pojo {
public String id;
public User user;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
public static class User {
public String username;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
}
}
The mapper creates a Pojo object with the values filled in. Then you can use that object for anything you need.
Here are a couple of links for the Jackson project:
http://jackson.codehaus.org/
http://wiki.fasterxml.com/JacksonInFiveMinutes
The latest all in one JAR is here:
http://jackson.codehaus.org/1.9.1/jackson-all-1.9.1.jar
You should try JavaJson from source forge... you can parse that this way:
JsonObject json = JsonObject.parse("...");
/*
* or also JsonObject.parse(inputStream);
*/
then you can get fields this way:
String title = json.getString("title");
String username = json.get("user", "username").toString();
and so on. here's the link: https://sourceforge.net/projects/javajson/