I have a rather JSON response coming back from a solr instance....
{"responseHeader":
{"status":0,"QTime":1,"params":{"sort":"score asc","fl":"*,score",
"q":"{! score=distance}","wt":"json","fq":"description:motor","rows":"1"}},
"response":{"numFound":9,"start":0,"maxScore":6.8823843,"docs":
[{"workspaceId":2823,"state":"MN","address1":"1313 mockingbird Lane",
"address2":"","url":"http://mydomain.com/","city":"Minneapolis",
"country":"US","id":"399068","guid":"","geo":["45.540239, -98.580473"],
"last_modified":"2012-12-12T20:40:29Z","description":"ELEC MOTOR",
"postal_code":"55555","longitude":"-98.580473","latitude":"45.540239",
"identifier":"1021","_version_":1421216710751420417,"score":0.9288697}]}}
And I'm trying to map that to a java object:
public class Item extends BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
protected Integer workspaceId;
protected String name;
protected String description;
protected String identifier;
protected String identifierSort;
protected Address address;
protected String url;
/** getters and setters eliminated for brevity **/
}
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
protected String address1;
protected String address2;
protected String city;
protected String state;
protected String postalCode;
protected String country;
/** getters and setters eliminated for brevity **/
}
How do I map the address1, address2, city, state, etc... into the Address object in the Item object? I've been reading about Jackson annotations but nothing really jumps out at me as to where to begin.
If using Jackson 1.9 or higher you can use the #JsonUnwrapped annotation to handle this.
Here is an example of using it (largely lifted from Jackson's documentation):
public class Name {
private String first, last;
// Constructor, setters, getters
}
public class Parent {
private int age;
#JsonUnwrapped
private Name name;
// Constructor, setters, getters
}
public static void main(String[] args) {
try {
final ObjectMapper mapper = new ObjectMapper();
final Parent parent = mapper.readValue(new File(
"/path/to/json.txt"), Parent.class);
System.out.println(parent);
} catch (final Exception e) {
e.printStackTrace();
}
}
We ended up using Solrj - sort of.
We wrote our own SolrResult object that we fed to SolrJ like so:
List<SolrResult> solrResults = rsp.getBeans(SolrResult.class);
And then in SolrResult.java where we had complex or nested objects we just first used SolrJ annotation to get the field and then just set the value as needed...
#Field("address1")
public void setAddress1(String address1) {
this.item.getAddress().setAddress1(address1);
}
It wasn't hard just feels a bit messy, but it does work.
Related
I have an input object as
class Person {
private String name;
private String email;
private String phone;
private Address address;
public static class Address {
private String city;
private String pincode;
private String street;
private AddrDetails details;
public static class AddrDetails {
private String state;
private String country;
}
}
}
I am using vavr Validations to validate the input
public static Validation<Seq<ConstraintViolation>, PersonDetailsModel> validatePerson(PersonDetailsRequest request) {
Validation
.combine(
validateName("name", request.getName()),
validateEmail("email", request.getEmail()),
validatePhone("phone", request.getPhone()),
validateAddress(request.getAddress())
).ap((name, email, phone, address) -> new PersonDetailsModel(name, email, phone, address);
}
public static Validation<Seq<ConstraintViolation>, Person.Address> validateAddress(
Person.Address request) {
return Validation
.combine(..
).ap((..) -> new Person.Address(..);
}
In the second function, it returns Seq of ConstraintViolation while validatePerson expects only ConstraintViolation which is why it is failing although I have to add one more level of nesting of validations for AddrDetails. How to handle nested objects validations with this approach.
I am not sure about how shall I go ahead?
In our project we call .mapError(Util::flattenErrors) after .ap. I have the feeling that there is a better way, but this at least solves the nesting.
The method in the Util class looks like this :
public static Seq<ConstraintViolation> flattenErrors(final Seq<Seq<ConstraintViolation>> nested) {
return nested
.flatMap(Function.identity())
.distinct(); // duplicate removal
}
I have entity class
public Class StudentEntity{
private int id;
private String name;
private AddressEntity address;
private ProfileEntity profile;
//getter setter
}
public Class StudentDTO{
private int id;
private String name;
private AddressDTO address;
private ProfileDTO profile;
//getter setter
}
when I use BeanUtils.copyProperties(); (from spring/apache common) it copies the id and name alone. How to copy the address and profile also?
If custom util has to be written, could you please share the snippet?
BeanUtils, cloning OR serialization would not work here as the inner data types are different. I would suggest you to set the fields of StudentDTO manually. You could use conversion constructor for AddressDTO and ProfileDTO. Copy constructor is the legal name, but since we are converting type also, better name would be a conversion constructor instead.
An example of conversion constructor in JDK is ArrayList(Collection<? extends E> c) , i.e. https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#ArrayList-java.util.Collection- which generates an ArrayList from any Collection object and copy all items from Collection object to newly created ArrayList object.
Example:
StudentEntity studentEntityObj = new StudentEntity();
studentEntityObj.setId(1);
studentEntityObj.setName("myStudent");
AddressEntity addressEntityObj = new AddressEntity();
addressEntityObj.setCity("myCity");
studentEntityObj.setAddress(addressEntityObj);
// All above lines would be taken care of already (i.e. data is filled from DB)
StudentDTO studentDTOObj = new StudentDTO();
// Call conversion constructor
AddressDTO addressDtoObj = new AddressDTO(addressEntityObj);
studentDTOObj.setAddress(addressDtoObj);
studentDTOObj.setId(studentEntityObj.getId());
studentDTOObj.setName(studentEntityObj.getName());
System.out.println(studentDTOObj.toString());
where AddressDTO (OR ProfileDTO for that matter) including a conversion constructor looks like:
public class AddressDTO {
private String city;
// Conversion constructor
public AddressDTO(AddressEntity a) {
this.city = a.getCity();
}
#Override
public String toString() {
return "AddressDTO [city=" + getCity() + "]";
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
prints
StudentDTO [id=1, name=myStudent, address=AddressDTO [city=myCity]]
You can try to use SerializationUtils.clone(). This method deep clone your object. But you should mark your objects as Serializable.
https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/SerializationUtils.html#clone(T)
Let's pretend I have the following XML:
<company name="Sun" country="Atlantis" state="Syracuse" city="Troy">
</company>
With JAXB, and without using third-party extensions such as EclipseLink's #XmlPath, is there a way to unmarshall it into the following POJO structure:
#XmlRootElement
public class Company {
private String name;
private Address address;
// getters and setters
}
public class Address {
private String country;
private String state;
private String city;
// getters and setters
}
company.getAddress().getCountry(); // Atlantis
This particular scenario can be handled using an XmlAdapter:
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.time.format.DateTimeFormatter;
public class CompanyAdapter extends XmlAdapter<CompantType, Company> {
#Override
public CompanyType marshal(Company in) throws Exception {
CompanyType out = new CompanyType();
out.setName(in.getName());
out.setCountry(in.getAddress().getCountry());
// ...
return out;
}
#Override
public Company unmarshall(CompanyType in) throws Exception {
Company out = new Company();
out.setName(in.getName());
Address add = new Address();
add.setCountry(in.getCountry());
out.setAddress(add);
// ...
return out;
}
}
I have below json string :-
{"name":"Test","sortlist":[],"filterlist":[{"fieldname":"regions_id","operator":"equals","value":{"id":1,"code":"HIGH","description":"HIGH Region","comment":"High Region","active":true}}]}
and Java class as below :-
#JsonSerialize
#JsonDeserialize
public class ItemFilter implements Serializable {
private String name;
private List<FieldFilter> filterlist = new ArrayList<FieldFilter>();
}
public class FieldFilter implements Serializable {
private static final long serialVersionUID = 1L;
private String fieldname;
private String operator;
private Object value;
}
and my convert method as below :-
public static ItemFilter convertItemFilter(String item) {
ObjectMapper mapper = new ObjectMapper();
try {
ItemFilter itemFilter = mapper.readValue(item, new TypeReference<ItemFilter>(){});
return itemFilter;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
ItemFilter domain is getting converted correctly but in private Object value; field i am getting LinkedHashMap i want to get an simple object and later i will type cast it.
Can someone please guide me how to escape LinkedHashMap and get an simple Java Object in variable?
i cant use hard coding Object type because its a generic pojo which can have any object type. hard coding will make this pojo very bigger and frontend also need to change for it. So that why i have used Object as data type.
The following class structure should return the JSON to "YourObject"
public class YourObject{
private String name;
private List<String> sortList;
private List<Filter> filterList;
public static class Filter{
private String fieldname;
private String operator;
private Value value;
}
public static class Value{
private Integer id;
private String code;
private String description;
private String comment;
private Boolean active;
}
}
Then use the following to read it into the object:
YourObject itemFilter = mapper.readValue(item, YourObject.class);
I have the following xml
<MyPojo>
<name>Jason</name>
<age>25</age>
<meta>
<occupation>Engineer</occupation>
</meta>
</MyPojo>
I need to deserialize it to the following POJO:
public class MyPojo {
private String name;
private int age;
private String occupation;
}
The problem here is that occupation is wrapped within meta element
You need one more object:
public class MyPojo {
private String name;
private int age;
private Meta meta;
}
public class Meta{
private String occupation;
}
My idea is to replace occupation with an own class. Something like myMeta or whatever you want to call it(be aware in your case like the xml says: meta). This class should cotain the field occupation:
public class Meta
{
private String occupation;
}
After that you only have to add a new field of your new class e.g. myMeta to myPojo. Something like this:
public class MyPojo
{
private String name;
private int age;
private Meta meta;
}
this should avoid
that occupation is wrapped within meta element
Hope that helps!