Whenever I select all my items from db, it is being returned as an array of objects. However I want the object to contain another object with data, instead of displaying everything in one JSON. Is this doable somehow?
Below is example which will return
[
{
"id": "",
"name": "",
"surname": "",
"date_started": "",
"school_name": "",
"graduated": false,
]
What I want:
[
{
"id": "",
"name": "",
"surname": "",
"date_started": "",
"school": {
"school_name": "",
"graduated": false,
}
]
public List<Person> getPeople() {
String sql = "my query";
List<Person> people = jdbcTemplate.query(sql, (result, index) -> {
return new People(
result.getObject("id", java.util.UUID.class),
result.getString("name"),
result.getString("surname"),
result.getDate("date_started"),
result.getString("school_name"),
result.getBoolean("graduated")
);
});
return people;
}
It is posible:
first create 2 class (bean / dto) such as:
public class peopleBean {
private int id;
private String name;
private String surname;
private String date_started;
private List<schoolBean> school;
...
}
public class schoolBean {
private String school_name;
private String graduated;
...
}
then in the getPeople corret it to use listpeople, people_local and school:
public List<Person> getPeople() {
String sql = "my query";
List<peobleBean> listpeople = new ArrayList<peopleBean>();
List<Person> people = jdbcTemplate.query(sql, (result, index) -> {
peopleBean people_local = new peopleBean();
schoolBean school = new schoolBean();
return new People(
result.getObject("id", java.util.UUID.class),
result.getString("name"),
result.getString("surname"),
result.getDate("date_started"),
result.getString("school_name"),
result.getBoolean("graduated")
);
});
return listpeople;
}
Related
I am relativly new to salesforce and apex programming. Recently I am assigned to get data from an external api. I am receiving an object which also has another object inside the main object. the data I am suppose to receive is as follows
{
"Product_Catagories": [{
"id": "8ad08aef8534de220185400383d82def",
"name": "Product One",
"description": "Desc One",
"region": "",
"category": "Main Products",
"ProductFamily": "Main",
"RelatedProducts": "POC-B0000001",
"productfeatures": []
}, {
"id": "8ad0887e8534de2701853fff5a9b22ee",
"name": "Product Two",
"description": "Desc Two",
"region": "",
"category": "Main Products",
"ProductFamily": "Main",
"RelatedProducts": "POC-B0000002",
"productfeatures": []
}, {
"id": "8ad08aef8534de2201853ffe48fc08f6",
"name": "Product Three",
"description": "Desc Three",
"region": "",
"category": "Main Products",
"ProductFamily": "Main",
"RelatedProducts": "POC-B0000003",
"productfeatures": []
}]
}
but i am getting
Product_Catagories:[category=null, description=null, id=null, name=null, productFamily=null, productfeatures=null, region=null, relatedProducts=null]
I have defined classes in apex code but the object is coming as empty. No data is showing. The code I am using is as follows
public class POCGetCategories {
public static List<Product_Catagories> getPOCCats(){
return new List<Product_Catagories>{getPOCProducts()};
}
public class Product_Catagories {
public String id;
public String name;
public String description;
public String region;
public String category;
public String productFamily;
public String relatedProducts;
public POCProductfeature productfeatures;
}
public class POCProductfeature {
public String id;
public String name;
public String code;
public String status;
public String description;
}
private static Product_Catagories getPOCProducts(){
Product_Catagories cats = new Product_Catagories();
Http h = new Http();
String method = 'GET';
String url = 'https://externalapi';
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod(method);
req.setTimeout(120000);
req.setHeader('Content-Type', 'application/jsson');
req.setHeader('subscription-Key','db163fc326d***');
HttpResponse res = h.send(req);
cats = (Product_Catagories)System.JSON.deserialize(res.getBody(), Product_Catagories.class);
system.debug('Data: ' + cats);
return cats;
}
}
The main response object is an object with a "Product_Catagories" key that contains an array of individual categories. The features key in each category is a list as well. Your model should look something like this:
public class ProductCatagoriesResponse {
public List<Product_Catagory> Product_Catagories;
}
public class Product_Catagory {
public String id;
public String name;
public String description;
public String region;
public String category;
public String productFamily;
public String relatedProducts;
public List<POCProductfeature> productfeatures;
}
...
ProductCatagoriesResponse cats = (ProductCatagoriesResponse)System.JSON.deserialize(res.getBody(), ProductCatagoriesResponse.class);
Also, it's spelled "category." But I'm assuming that's their typo and you just have to deal with it...
I have this object class that has a list of customers as an attribute:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class PeopleDTO {
private String processType;
private String operation;
private String entity;
private String entityType;
private Long id;
private Document document;
#Getter
#Setter
class Customer {
private String systemId;
private String customerId;
}
private List<Customer> customers;
}
This list is retrieved calling another microservice using webclient as follows:
public Mono<CuCoPerson> getCuCoPerson(Integer cucoId, String GS_AUTH_TOKEN) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", GS_AUTH_TOKEN)
.retrieve()
.bodyToMono(CuCoPerson.class)
.map(cuCoPerson -> {
List<CustomerRelation> matches = cuCoPerson.getRelatedCustomers()
.stream()
.filter(relation -> relation.getSystemId().equals(400) || relation.getSystemId().equals(300) || relation.getSystemId().equals(410))
.filter(relation -> relation.getCustomerId().contains("F"))
.collect(Collectors.toList());
cuCoPerson.setRelatedCustomers(matches);
return cuCoPerson;
});
}
This method return a cucoPerson as follows:
{
"id": 1,
"relatedCustomers": [
{
"customerId": "xxx",
"systemId": 999
}
]
}
So now I want to add this object to my PeopleDTO class, but I don't know how. This is what I've done son far (hardcoded):
public PeopleDTO createPeople(Long id) {
PeopleDTO people = new PeopleDTO();
people.setProcessType("ONLINE");
people.setOperation("UPDATE");
people.setEntity("DOCUMENT");
people.setEntityType("DOCUMENT");
people.setIdCuco(id);
people.setDocument(new Document());
people.setCustomers(......);
}
So as you can see I don't know how to add a Mono in the last line.
The expected result should be like this:
{
"type": "ONLINE",
"operation": "UPDATE",
"id": 1,
"entity": "DOCUMENT",
"entityType": "NIE",
"documents": {
"id": 1,
"additionals": {
"issuing_authority": "Spain",
"country_doc": "ES",
"place_of_birth": "",
"valid_from": "1995-08-09",
"valid_to": "0001-01-01"
},
"code": "X12345",
"typeDocument": "NIE"
},
"id": 1,
"relatedCustomers": [
{
"customerId": "xxx",
"systemId": 999
}
]
}
first, create a list of customers like:
List<Customer> customers=new ArrayList<>;
Then add all the Customers to it one by one using a loop,
then you can directly add that to your object like
people.setCustomers(customers);
your object assignment should look something like:
public PeopleDTO createPeople(Long id) {
PeopleDTO people = new PeopleDTO();
people.setProcessType("ONLINE");
people.setOperation("UPDATE");
people.setEntity("DOCUMENT");
people.setEntityType("DOCUMENT");
people.setIdCuco(id);
people.setDocument(new Document());
List<Customer> customers=new ArrayList<>;
//add data to customer
people.setCustomers(customers);
}
I have data which arrives as such (list of maps):
{
“name”: “Hello”,
"source": “One”,
"status": “Good”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Hello”,
"source": “Two”,
"status": “Good”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Goodbye”,
"source": “Three”,
"status": “Bad”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Goodbye”,
"source": “Four”,
"status": “Bad”,
“date”: "01-05-2021 7:35:58 PM"
}
So I want to group this data by “name”, but also create a new field which collects the “source” and “status” fields into a list of objects. This would mean I'd have to map the inner data to a Java class as well (call these individual objects “sourceStatus” which I've already created a class for).
{
“name”: “Hello”,
“sourceStatuses”: [
{
“source”: ”One”,
“status”: ”Good”
},
{
“source”: ”Two”,
“status”: ”Good”
}
],
“status”: “Good”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Goodbye”,
“sourceStatuses”: [
{
“source”: ”Three”,
“status”: ”Bad”
},
{
“source”: ”Four”,
“status”: ”Bad”
}
],
“status” : “Bad,
“date”: "01-05-2021 7:35:58 PM"
}
I understand the groupingBy part can be done fairly straightforwardly with Java's Collector (https://www.baeldung.com/java-groupingby-collector), but I'm not sure how to achieve the resultant set for my use case, where I not only create a new field but am also collecting then mapping inner data to a class.
Edit: "date" and "status" are going to be the same for all items with the same "name".
I found no easy way to do it with just one grouping but here is a somewhat more complicated two stage solution.
public class Main {
public static void main(String[] args) {
List<Map<String, String>> data = new ArrayList<>();
data.add(newData("Hello", "One", "Good", "01-05-2021 7:35:58 PM"));
data.add(newData("Hello", "Two", "Good", "01-05-2021 7:35:58 PM"));
data.add(newData("Goodbye", "Three", "Bad", "01-05-2021 7:35:58 PM"));
data.add(newData("Goodbye", "Four", "Bad", "01-05-2021 7:35:58 PM"));
Map<Key, List<SourceStatus>> collected = data.stream()
.collect(Collectors.groupingBy(
m -> new Key(m.get("name"), m.get("status"), m.get("date")),
Collectors.collectingAndThen(Collectors.toList(), m -> m.stream().map(e -> new SourceStatus(e.get("source"), e.get("status"))).collect(Collectors.toList()))
));
List<CollectedData> finalCollection = collected.entrySet().stream()
.map(e -> new CollectedData(e.getKey().name, e.getValue(), e.getKey().status, e.getKey().date))
.collect(Collectors.toList());
finalCollection.forEach(System.out::println);
}
private static Map<String, String> newData(String name, String source, String status, String date) {
Map<String, String> map = new HashMap<>();
map.put("name", name);
map.put("source", source);
map.put("status", status);
map.put("date", date);
return map;
}
private static class Key {
private final String name;
private final String status;
private final String date;
public Key(String name, String status, String date) {
this.name = name;
this.status = status;
this.date = date;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
return Objects.equals(name, key.name) && Objects.equals(status, key.status) && Objects.equals(date, key.date);
}
#Override
public int hashCode() {
return Objects.hash(name, status, date);
}
}
}
Two more classes needed:
public class SourceStatus {
private final String source;
private final String status;
public SourceStatus(String source, String status) {
this.source = source;
this.status = status;
}
// Getters, equals/hashCode and toString
}
public class CollectedData {
private final String name;
private final List<SourceStatus> sourceStatuses;
private final String status;
private final String date;
public CollectedData(String name, List<SourceStatus> sourceStatuses, String status, String date) {
this.name = name;
this.sourceStatuses = sourceStatuses;
this.status = status;
this.date = date;
}
// Getters, equals/hashCode and toString
}
Not my finest code...
The key for the groupingBy collector should be another modifiable map without key "source" and the value should be a list of SourceStatus class, which can be collected using Collectors.mapping collector.
Note: Map's are used to represent a key and a final result deliberately.
Let's assume, SourceStatus has a custom constructor using Map<String, Object> as an argument to use it in the Collectors.mapping:
public class SourceStatus {
private String source;
private String status;
public SourceStatus(Map<String, Object> map) {
this.source = (String) map.get("source");
this.status = (String) map.get("status");
}
}
Then the code to get the resulting set of maps is as follows:
Set<Map<String, Object>> mapped = data
.stream()
.collect(Collectors.groupingBy(
m -> {
Map<String, Object> key = new LinkedHashMap<>();
key.putAll(m);
key.remove("source");
return key;
},
Collectors.mapping(SourceStatus::new, Collectors.toList())
))
.entrySet().stream()
.map(e -> {
e.getKey().put("sourceStatuses", e.getValue());
return e.getKey();
})
.collect(Collectors.toCollection(LinkedHashSet::new)); // maintain insertion order
// convert to json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapped);
System.out.println(json);
Output:
[ {
"name" : "Hello",
"date" : "01-05-2021 7:35:58 PM",
"status" : "Good",
"sourceStatuses" : [ {
"source" : "1",
"status" : "Good"
}, {
"source" : "2",
"status" : "Good"
} ]
}, {
"name" : "Bye",
"date" : "01-05-2021 7:35:58 PM",
"status" : "Bad",
"sourceStatuses" : [ {
"source" : "3",
"status" : "Bad"
}, {
"source" : "4",
"status" : "Bad"
} ]
} ]
I want to create this JSON using jakson annotated POJOS. The issue I have when I create a new class without #JsonProperty annotation to represent the last {"id":"123ccc","role":"dddd"}, it by default take the class name and create something like "customer":{"id": "123ccc","role":"dddd"}.
The JSON Structure I indent to build
{
"relatedParty": [
{
"contact": [
{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
},
{
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}
],
"role": "ccc",
"fullName": "ccc"
},
{
"id": "123ccc",
"role": "dddd"
}
]
}
The JSON I'm receiving from the below code.
{
"relatedParty": [
{
"contact": [
{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
},
{
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}
],
"role": "ccc",
"fullName": "ccc"
},
"customer" : {
"id": "123ccc",
"role": "dddd"
}
]
}
What would be a workaround to get the exact JSON format as the image. Current Implementation is below.
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class RelatedParty {
#JsonProperty(value = "contact")
private List<Contact> contact;
#JsonProperty(value = "role")
private String role;
#JsonProperty(value = "fullName")
private String fullName;
private Customer customer;
public List<Contact> getContact() {
return contact;
}
public void setContact(List<Contact> contact) {
this.contact = contact;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
public class Customer {
#JsonProperty(value = "id")
private String id;
#JsonProperty(value = "role")
private String role;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
You need to create additional and different POJO classes to model your JSON correctly. Basically, JSON arrays will be handle in Java lists, and JSON objects will be handled in Java classes.
Starting from the inside (most nested level) of the JSON, and working our way out:
NOTE: getters and setters not shown here
Characteristic.java
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Characteristic {
#JsonProperty("city")
private String city;
#JsonProperty("country")
private String country;
#JsonProperty("emailAddress")
private String emailAddress;
}
Contact.java (contains our characteristics):
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Contact {
#JsonProperty("mediumType")
private String mediumType;
#JsonProperty("characteristic")
private Characteristic characteristic;
}
The above two classes handle the innermost objects. If we remove them from your target JSON, that leaves the following:
{
"relatedParty": [{
"contact": [...],
"role": "ccc",
"fullName": "ccc"
}, {
"role": "dddd",
"id": "123ccc"
}]
}
Note that the contact field is a JSON array, not an object - so we do not create a Java Contact class (which would be for a JSON object).
To handle the above I create two more classes:
RelatedPartyInner.java (contains a list of contacts)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class RelatedParty_ {
#JsonProperty("contact")
private List<Contact> contact = null;
#JsonProperty("role")
private String role;
#JsonProperty("fullName")
private String fullName;
#JsonProperty("id")
private String id;
}
RelatedParty.java (wraps everything in an outer object):
#JsonInclude(JsonInclude.Include.NON_NULL)
public class RelatedParty {
#JsonProperty("relatedParty")
private List<RelatedPartyInner> relatedParty = null;
}
To test this I create the following data:
Characteristic chr1 = new Characteristic();
chr1.setCity("xxx");
chr1.setCountry("xxx");
Characteristic chr2 = new Characteristic();
chr2.setEmailAddress("yyy#yy.yyy");
Contact con1 = new Contact();
con1.setMediumType("xxx");
con1.setCharacteristic(chr1);
Contact con2 = new Contact();
con2.setMediumType("yyy");
con2.setCharacteristic(chr2);
List<Contact> cons = new ArrayList<>();
cons.add(con1);
cons.add(con2);
RelatedPartyInner rpi1 = new RelatedPartyInner();
rpi1.setContact(cons);
rpi1.setRole("ccc");
rpi1.setFullName("ccc");
RelatedPartyInner rpi2 = new RelatedPartyInner();
rpi2.setId("123ccc");
rpi2.setRole("dddd");
List<RelatedPartyInner> rpis = new ArrayList<>();
rpis.add(rpi1);
rpis.add(rpi2);
RelatedParty rp = new RelatedParty();
rp.setRelatedParty(rpis);
Finally, we can generate the JSON:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(new File("rp.json"), rp);
The resulting file contains the following:
{
"relatedParty": [{
"contact": [{
"mediumType": "xxx",
"characteristic": {
"city": "xxx",
"country": "xxx"
}
}, {
"mediumType": "yyy",
"characteristic": {
"emailAddress": "yyy#yy.yyy"
}
}],
"role": "ccc",
"fullName": "ccc"
}, {
"role": "dddd",
"id": "123ccc"
}]
}
I am making a restaurant management app and I am having a problem persisting a user association. For the Chef class there is a set association with the Dish class so that specific dishes can be associated with a certain chef.
I have created a method that associates a dish with a chef, and when I try calling it on my REST client the method seems to work, and it returns a JSON of the chef object with the updated info, however when I call the get chef method the JSON no longer shows the added dish item
Here is the chef class and everything related to the Dish Object
#Table(name="chef")
public class Chef {
//Chef Attributes
#Id private String username;
private String firstName;
private String lastName;
private String email;
private String password;
private String address;
private String bio;
private Boolean delivery;
private String photoURL;
// #OneToOne
// private ChefMenu menu;
#Transient
#OneToMany(mappedBy = "chef", cascade = CascadeType.ALL)
#JsonIgnoreProperties("chef")
private Set<Dish> menuItems;
public Set<Dish> getMenuItems() {
if (this.menuItems == null) {
this.menuItems = new HashSet<Dish>();
}
return this.menuItems;
}
Here is the Dish class with everything related to the Chef class
#Entity
#Table(name="dish")
public class Dish {
//Dish Attributes
#Id private String dishName;
private String cuisine;
private double price;
private String maxQuantity;
private String dietaryRestriction;
private String mealIngredients;
private String cookingTime;
#ManyToOne
#JoinColumn(name = "chef")
#JsonIgnoreProperties({"menuItems","orders","firstName", "lastName", "email", "bio", "password", "address", "delivery", "photoURL"})
private Chef chef;
public void setChef(Chef val) { this.chef = val; }
public Chef getChef() {
return this.chef;
}
Here is the method used to add a new dish to a chef from the repository
#Transactional
public Chef addDishToMenu(Chef c, Dish d) {
c.addDish(d);
entityManager.merge(c);
return c;
}
And finally here is code from the controller class:
#PostMapping("dish/create/{dishName}/{cuisine}/{price}/{maxQuantity}/{dietaryRestriction}/{mealIngredients}/{cookingTime}")
public ResponseEntity createDish(String username,
#PathVariable("dishName") String dishName, #PathVariable("cuisine") String cuisine,
#PathVariable("price") String price, #PathVariable("maxQuantity") String maxQuantity,
#PathVariable("dietaryRestriction") String dietaryRestriction,
#PathVariable("mealIngredients") String mealIngredients, #PathVariable("cookingTime") String cookingTime)
{
Dish d = new Dish();
Double p = Double.parseDouble(price);
//int mQ = Integer.parseInt(maxQuantity);
try {
d = foodRepository.createDish(dishName, cuisine, p, maxQuantity, dietaryRestriction,
mealIngredients, cookingTime);
} catch (InvalidInputException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new Response(false, e.getMessage()));
}
return ResponseEntity.status(HttpStatus.OK).body(d);
}
#PostMapping("dish/add/{username}/{dishName}")
public ResponseEntity addDishToMenu(#PathVariable("username") String username, #PathVariable("dishName") String dishName) throws NullObjectException {
Chef c = new Chef();
Dish d = new Dish();
c= chefRepository.getChef(username);
d = foodRepository.getSpecificDish(dishName);
c = foodRepository.addDishToMenu(c, d);
return ResponseEntity.status(HttpStatus.OK).body(c);
}
#GetMapping("/get/{username}")
public ResponseEntity getChef(#PathVariable("username") String username) {
// List<AppUser> user;
Chef chef = new Chef();
try {
chef = chefRepository.getChef(username);
// user = userRepository.getAppUserQuery(username);
} catch (NullObjectException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new Response(false, e.getMessage()));
}
return ResponseEntity.status(HttpStatus.OK).body(chef);// user.get(0));
}
So when I make the call on my Rest client to add a dish to a chef I get this as a response:
{
"username": "Favreau4",
"firstName": "Jon",
"lastName": "Favreau",
"email": "chefFavreau#email.com",
"password": "j+9UECq/PLA=$I+HsXngf/b82+rMtPQQO",
"address": null,
"bio": null,
"delivery": null,
"photoURL": null,
"menuItems": [
{
"dishName": "Big sandwich",
"cuisine": "american",
"price": 5,
"maxQuantity": "3",
"dietaryRestriction": "bacon",
"mealIngredients": "bacon,lettuce,tomato,bread",
"cookingTime": "10mins"
}
],
"order": [],
}
but when I use the getChef REST call I get this:
{
"username": "Favreau4",
"firstName": "Jon",
"lastName": "Favreau",
"email": "chefFavreau#email.com",
"password": "j+9UECq/PLA=$I+HsXngf/b82+rMtPQQO",
"address": null,
"bio": null,
"delivery": null,
"photoURL": null,
"menuItems": [],
"order": [],
}
Does anyone know how to resolve this issue?
Are you aware of #Transient annotation? Transient are used to mark a variable as non-presistable. So your menuitems are not getting persist or saved in database.