Accessing POJO Class in Spring - spring

I am new to Spring, Currently i am facing a difficulty to access a method of a POJO class through another POJO class.
This is my JSON
[{
"name": "foo",
"albums": [
{
"title": "album_one",
"artist": "foo",
"ntracks": 12
},
{
"title": "album_two",
"artist": "foo",
"ntracks": 15
}
]},{
"name": "bar",
"albums": [
{
"title": "foo walks into a bar",
"artist": "bar",
"ntracks": 12
},
{
"title": "album_song",
"artist": "bar",
"ntracks": 17
}
]}]
This my classes
public class ArtistInfo {
private String name;
private List<Album> albums;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public List<Album> getAlbums() {return albums;}
public void setAlbums(List<Album> albums) {this.albums = albums;}
}
public static class Album {
private String title;
private String artist;
private int ntracks;
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public String getArtist() {return artist;}
public void setArtist(String artist) {this.artist = artist;}
public int getNtracks() {return ntracks;}
public void setNtracks(int ntracks) {this.ntracks = ntracks;}
}
I want to access getTitle() method of Album Class through ArtistInfo class like:
ArtistInfo artistinfo = new ArtistInfo();
artistinfo.getAlbums().getTitle();
I know this was wrong because artistinfo.getAlbums() return a list it doesn't return object. If i add another field (Object for Album class in ArtistInfo ) it affect the Json format, if any way to acess getTitle() from artistinfo class or any modification in ArtistInfo class will help to acess it.
Please help me to solve this..........
Thank you in advance.

To get all the titles of an artist you can use the following code
List<String> titles = artistInfo.getAlbums()
.stream()
.map(Album::getTitle)
.collect(Collectors.toList());

Related

How to use Jackson for parse object follow json type?

I have two Json objects like :
Object 1
{
"value": {
"data": [
"John",
"Justin",
"Tom"
],
"isGraduated": false
}
}
Object 2
{
"value": {
"data": {
"info": {
"background": {
"primarySchool" : "A school",
"univeristy": "X univeristy"
},
"name": "John",
"gender": "male",
"dayOfBirth": "1995-04-24"
}
},
"isGraduated": false
}
}
How can I deserialize the data field to list of strings or class(I've already declared) by using Jackson?
Edit
Add class Info declaration.
public class Info {
#JsonProperty("background")
private BackGround backGround;
#JsonProperty("name")
private String name;
#JsonProperty("gender")
private String gender;
#JsonProperty("dayOfBirth")
private String dayOfBirth;
public static class BackGround {
#JsonProperty("primarySchool")
private String primarySchool;
#JsonProperty("univeristy")
private String univeristy;
}
}
Looking at your JSON objects, there is no way you can figure out what will be there in data parameter. So you can use JsonNode as type for data parameter.
Note: This is the object hierarchy I have created to represent JSON objects
#ToString
class Wrapper {
private Value value;
// getter & setter
}
#ToString
class Value {
private JsonNode data;
private Boolean isGraduated;
// getter & setter
}
#ToString
class Data {
private Info info;
// getter & setter
}
#ToString
class Info {
private Background background;
private String name;
private String gender;
private String dayOfBirth;
// getter & setter
#ToString
static class Background {
private String primarySchool;
private String univeristy;
// getter & setter
}
}
Then you can check the node type before deserialize between List<String> and Info.calss like this,
JsonNodeType type = value.getValue().getData().getNodeType();
You will see type = JsonNodeType.ARRAY if the json object is type 1 and type = JsonNodeType.OBJECT if the json object is type 2.
Check this exaple,
public class Main {
public static void main(String[] args) throws IOException {
// String s = "{\"value\":{\"data\":[\"John\",\"Justin\",\"Tom\"],\"isGraduated\":false}}";
String s = "{\"value\":{\"data\":{\"info\":{\"background\":{\"primarySchool\":\"A school\",\"univeristy\":\"X univeristy\"},\"name\":\"John\",\"gender\":\"male\",\"dayOfBirth\":\"1995-04-24\"}},\"isGraduated\":false}}";
ObjectMapper om = new ObjectMapper();
Wrapper wrapper = om.readValue(s, Wrapper.class);
JsonNodeType type = wrapper.getValue().getData().getNodeType();
if (type == JsonNodeType.ARRAY) {
List<String> data = om.convertValue(wrapper.getValue().getData(), new TypeReference<List<String>>() {});
System.out.println(data);
} else if (type == JsonNodeType.OBJECT) {
Data data = om.convertValue(wrapper.getValue().getData(), Data.class);
System.out.println(data);
}
}
}
Not the general approach but approach for your specific case
ObjectMapper mapper = new ObjectMapper();
ObjectNode root = (ObjectNode) mapper.readTree(jsonContent);
JsonNode data = root.get("value").get("data");
if (data.has("info")) {
Info result = mapper.convertValue(data.get("info"), Info.class);
// handle result as Info instance
} else {
List<String> result = mapper.convertValue(data, new TypeReference<List<String>>() {});
// handle result as list of strings
}

Spring Boot - Get Data from DB and store it in list and parse it to JSON using jackson

I'm trying to get data from multiple tables and put it in Array List of class, and then convert it to JSON Object.
But when i'm trying to parse it to json using Jackson Object Mapper all the lists are converted as below
Using ObjectMapper().writeValueAsString for deserialization from class objects to json
```{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
},
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
},
{
"star": "2"
"comments": "ok"
},
}
]
}```
But i want the result as below
{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
}
]
},
{
"institution": [
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "2"
"comments": "ok"
}
]
}
]
}
The above is just an example.
Please help in getting the desired output.
Below are the class files used.
public class AllCollege{
List<College> college = new ArrayList<>();
public List<College> getCollege() {
return college;
}
public void setCollege(List<College> college) {
this.college = college;
}
}
public class College{
private List<Institution> institution = new ArrayList<>();
private List<Rating> rating = new ArrayList<>();
public List<Institution> getInstitution() {
return institution;
}
public void setInstitution(List<Institution> institution) {
this.institution = institution;
}
public List<Rating> getRating() {
return rating;
}
public void setRating(List<Rating> rating) {
this.rating = rating;
}
}
public class Institution {
private String instId;
private String country;
private String code;
public String getInstId() {
return instId;
}
public void setInstId(String instId) {
this.instId = instId;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
public class Rating {
private String star;
private String comments;
public String getStar() {
return star;
}
public void setStar(String star) {
this.star = star;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
}
Below is where the data from tables is set into ArrayList and then converted to json string.
session = sessionFactory.openSession();
String sql = "from institution";
Query<InstDto> query = session.createQuery(sql);
List<Institution> configdtoList =query.list();
College alc = new College();
alc.setInstitution(configdtoList);
.
.
.
similarly Rating table.
List<College> clist = new new ArrayList<>();
clist.add(alc);
AllCollege ac = new AllCollege();
ac.setCollege(clist);
String responseJson = new ObjectMapper().writeValueAsString(ac)
class structure as below it will help you to parse:
public class Sample {
#JsonProperty("College")
private List<College> college;
}
public class College {
private List<Institution> institution;
#JsonProperty("Rating")
private List<Rating> rating;
}
public class Rating {
private String comments;
private String star;
}
public class Institution {
#JsonProperty("Code")
private String code;
#JsonProperty("Country")
private String country;
private String instId;
}
I have created an HashMap contains the List<AllCollege> as value and then used json parser which worked as expected.

Expose enums with Spring Data REST

I'm using Spring Boot 1.5.3, Spring Data REST, HATEOAS.
I've a simple entity model:
#Entity
public class User extends AbstractEntity implements UserDetails {
private static final long serialVersionUID = 5745401123028683585L;
public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
#NotNull(message = "The name of the user cannot be blank")
#Column(nullable = false)
private String name;
/** CONTACT INFORMATION **/
private String landlinePhone;
private String mobilePhone;
#NotNull(message = "The username cannot be blank")
#Column(nullable = false, unique = true)
private String username;
#Email(message = "The email address is not valid")
private String email;
#JsonIgnore
private String password;
#Column(nullable = false)
private String timeZone = "Europe/Rome";
#JsonIgnore
private LocalDateTime lastPasswordResetDate;
#Column(nullable = false, columnDefinition = "BOOLEAN default true")
private boolean enabled = true;
#Type(type = "json")
#Column(columnDefinition = "json")
private Roles[] roles = new Roles[] {};
and my enum Roles is:
public enum Roles {
ROLE_ADMIN, ROLE_USER, ROLE_MANAGER, ROLE_TECH;
#JsonCreator
public static Roles create(String value) {
if (value == null) {
throw new IllegalArgumentException();
}
for (Roles v : values()) {
if (value.equals(v.toString())) {
return v;
}
}
throw new IllegalArgumentException();
}
}
I'm creating a client in Angular 4. Spring Data REST is great and expose repository easily return my model HATEOAS compliant:
{
"_embedded": {
"users": [
{
"name": "Administrator",
"username": "admin",
"roles": [
"Amministratore"
],
"activeWorkSession": "",
"_links": {
"self": {
"href": "http://localhost:8080/api/v1/users/1"
},
"user": {
"href": "http://localhost:8080/api/v1/users/1{?projection}",
"templated": true
}
}
},
Like you can see I'm also translating via rest-messages.properties the value of my enums. Great!
My Angular page now needs the complete lists of roles (enums). I've some question:
understand the better way for the server to return the list of roles
how to return this list
My first attemp was to create a RepositoryRestController in order to take advantage of what Spring Data REST offers.
#RepositoryRestController
#RequestMapping(path = "/api/v1")
public class UserController {
#Autowired
private EntityLinks entityLinks;
#RequestMapping(method = RequestMethod.GET, path = "/users/roles", produces = "application/json")
public Resource<Roles> findRoles() {
Resource<Roles> resource = new Resource<>(Roles.ROLE_ADMIN);
return resource;
}
Unfortunately, for some reason, the call to this methods return a 404 error. I debugged and the resource is created correctly, so I guess the problem is somewhere in the JSON conversion.
how to return this list?
#RepositoryRestController
#RequestMapping("/roles")
public class RoleController {
#GetMapping
public ResponseEntity<?> getAllRoles() {
List<Resource<Roles>> content = new ArrayList<>();
content.addAll(Arrays.asList(
new Resource<>(Roles.ROLE1 /*, Optional Links */),
new Resource<>(Roles.ROLE2 /*, Optional Links */)));
return ResponseEntity.ok(new Resources<>(content /*, Optional Links */));
}
}
I was playing around with this and have found a couple of ways to do it.
Assume you have a front end form that wants to display a combo box containing priorities for a single Todo such as High, Medium, Low. The form needs to know the primary key or id which is the enum value in this instance and the value should be the readable formatted value the combo box should display.
If you wish to customize the json response in 1 place only such as a single endpoint then I found this useful. The secret sauce is using the value object PriorityValue to allow you to rename the json field through #Relation.
public enum Priority {
HIGH("High"),
NORMAL("Normal"),
LOW("Low");
private final String description;
Priority(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static List<Priority> orderedValues = new ArrayList<>();
static {
orderedValues.addAll(Arrays.asList(Priority.values()));
}
}
#RepositoryRestController
#RequestMapping(value="/")
public class PriorityController {
#Relation(collectionRelation = "priorities")
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
private class PriorityValue {
private String id;
private String value;
public PriorityValue(String id,
String value) {
this.id = id;
this.value = value;
}
}
#GetMapping(value = "/api/priorities", produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<Resources<PriorityValue>> getPriorities() {
List<PriorityValue> priorities = Priority.orderedValues.stream()
.map(p -> new PriorityValue(p.name(), p.getDescription()))
.collect(Collectors.toList());
Resources<PriorityValue> resources = new Resources<>(priorities);
resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());
return ResponseEntity.ok(resources);
}
}
Another approach is to use a custom JsonSerializer. The only issue using this is everywhere a Priority enum is serialized you will end up using this format which may not be what you want.
#JsonSerialize(using = PrioritySerializer.class)
#Relation(collectionRelation = "priorities")
public enum Priority {
HIGH("High"),
NORMAL("Normal"),
LOW("Low");
private final String description;
Priority(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static List<Priority> orderedValues = new ArrayList<>();
static {
orderedValues.addAll(Arrays.asList(Priority.values()));
}
}
#RepositoryRestController
#RequestMapping(value="/api")
public class PriorityController {
#GetMapping(value = "/priorities", produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<Resources<Priority>> getPriorities() {
Resources<Priority> resources = new Resources<>(Priority.orderedValues);
resources.add(linkTo(methodOn(PriorityController.class).getPriorities()).withSelfRel());
return ResponseEntity.ok(resources);
}
}
public class PrioritySerializer extends JsonSerializer<Priority> {
#Override
public void serialize(Priority priority,
JsonGenerator generator,
SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
generator.writeStartObject();
generator.writeFieldName("id");
generator.writeString(priority.name());
generator.writeFieldName("value");
generator.writeString(priority.getDescription());
generator.writeEndObject();
}
}
The final json response from http://localhost:8080/api/priorities
{
"_embedded": {
"priorities": [
{
"id": "HIGH",
"value": "High"
},
{
"id": "NORMAL",
"value": "Normal"
},
{
"id": "LOW",
"value": "Low"
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/api/priorities"
}
}
}

How to post to a URL with hash + range key Spring Data DynamoDB

As in spring-data-dynamoDB demo, I have created my application with hash and range keys, but am unable to post any data into my Table using POST because the following exception,
{cause: {cause: {cause: null,message: null}, message: "N/A (through reference chain: pkg.Test["id"])"}, message: "Could not read JSON: N/A (through reference chain: pkg.Test["id"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: N/A (through reference chain: pkg["id"])"
}
My Domain Class,
#DynamoDBTable(tableName = "test")
public class Test implements Serializable{
private static final long serialVersionUID = 1L;
#Id private TestId testId;
private String description;
private String testing;
#DynamoDBHashKey(attributeName="id")
public String getId() {
return testId != null ? testId.getId() : null;
}
public void setId(String id) {
if(testId == null){
testId = new TestId();
}
this.setId(id);
}
#DynamoDBRangeKey(attributeName="name")
public String getName() {
return testId != null ? testId.getName() : null;
}
public void setName(String name) {
if(testId == null){
testId = new TestId();
}
this.setName(name);
}
#DynamoDBAttribute(attributeName="description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#DynamoDBAttribute(attributeName="testing")
public String getTesting() {
return testing;
}
public void setTesting(String testing) {
this.testing = testing;
}
public TestId getTestId() {
return testId;
}
public void setTestId(TestId testId) {
this.testId = testId;
}
}
and my TestId Class,
public class TestId implements Serializable{
private String id;
private String name;
#DynamoDBHashKey
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#DynamoDBRangeKey
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I think I have created Domain class correctly but What is the correct procedure to Post data into it. I have tried,
URL:
http://localhost:8080/tests
Request Body:
{"testId": {"id": "test", "name": "z"}, "description": "Awesome Guy", "testing": "x"}
and
{"id": "test", "name": "z", "description": "Awesome Guy", "testing": "x"}
But all shows the exception as I mentioned above but I have given id attribute in requestbody correctly.
What is the correct procedure to POST the data into my table? and Is there anything problem with spring-data-rest parsing? as mentioned here
The setId() method seems to be self-calling. You may want to call testId.setId() instead of this.setId().

GSON,AndroidAnnotations - Expected BEGIN_OBJECT but was String

I searched similar topics but none of them helped me.
My JSON response is:
{
"success": "true",
"data": {
"id": "x",
"user_name": "xxx",
"email": "xxx#xxx.com",
"first_name": "xxx",
"last_name": "xx",
"position": "xxx",
"session_id": "xxx"
}
}
My Java classes are:
Response:
public class Response {
public String success;
public Data data;
public Response() {
}
public Response(String success, Data data) {
this.success = success;
this.data = data;
}
}
Data
public class Data {
public String id;
public String user_name;
public String email;
public String first_name;
public String last_name;
public String position;
public String session_id;
public Data() {
}
public Data(String id, String user_name, String email, String first_name, String last_name, String position, String session_id) {
this.id = id;
this.user_name = user_name;
this.email = email;
this.first_name = first_name;
this.last_name = last_name;
this.position = position;
this.session_id = session_id;
}
}
I am using android annotations to establish rest connection.
My RestClient is:
#Rest(rootUrl = "http://xxx/services", converters = {GsonHttpMessageConverter.class})
public interface MyRestClient {
#Post("/login.php")
ResponseEntity<Response> login(User user);
RestTemplate getRestTemplate();
void setRestTemplate(RestTemplate restTemplate);
}
And in main activity I use:
ResponseEntity<Response> resp = restCli.login(new User("xxx","xxx"));
I get an error
Expected BEGIN_OBJECT but was String at line 1 column 4
I tried to change 'success' filed type to boolean,Boolean i Java class - didn't help.
I tried changing the method return type in the rest interface to void and then no error, so I think the error is connected with wrong response class, but I have no idea what is wrong. Could you help me?

Resources