I can't figure out how to handle nested JSON values in my Java classes. To make it simple as possible, I created four Java classes with every 'nested level'. However, I'm trying to have all these values in one Java class. How can I do this?
Json:
{
"_embedded":{
"events":[
{
"name":"KISS | End Of The Road World Tour",
"dates":{
"start":{
"dateTime":"2021-06-12T19:00:00Z"
},
"classifications":[
{
"name":"Rock"
}
],
"_embedded":{
"venues":[
{
"name":"Atlas Arena"
}
]
}
}
}
]
}
}
Java classes:
#Data
public class EventList {
#JsonProperty("_embedded")
private Events events;
}
#Data
public class Events {
#JsonProperty("events")
public List<EventDetails> eventsList;
}
#Data
public class EventDetails {
private String name;
#JsonProperty("dates.start.dateTime")
private String startDate;
#JsonProperty("classifications.genre.name")
private String musicType;
#JsonProperty("_embedded.venues")
private List<Venues> eventPlaceName;
}
#Data
public class Venues {
private String name;
}
You can club all the supporting classes in one class like below :
#Data
public class Start {
#JsonProperty("dateTime")
public Date dateTime;
public static class Venue {
#JsonProperty("name")
public String name;
}
#Data
public static class Classification {
#JsonProperty("name")
public String name;
}
#Data
public static class Embedded2 {
#JsonProperty("venues")
public List<Venue> venues;
}
#Data
public static class Dates {
#JsonProperty("start")
public Start start;
#JsonProperty("classifications")
public List<Classification> classifications;
#JsonProperty("_embedded")
public Embedded2 _embedded;
}
#Data
public static class Event {
#JsonProperty("name")
public String name;
#JsonProperty("dates")
public Dates dates;
}
#Data
public static class Embedded {
#JsonProperty("events")
public List<Event> events;
}
#Data
public static class Root {
#JsonProperty("_embedded")
public Embedded _embedded;
}
}
You can test (I am using Jackson for deserialization)
create ObjectMapper class and deserialize into a Root class
public class TestJson {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
try {
Start.Root root = objectMapper.readValue(new File("C:\\Anurag\\Development\\CodeBase\\demo\\src\\main\\java\\com\\example\\demo\\domain\\testJson\\test.json"), Start.Root.class);
System.out.println(root);
} catch (Exception e) {
e.printStackTrace();
}
}
}
-When debugging, you'll notice that our objects have been filled accordingly:
**Changes done as per your requiement **
#Data
public class EventList {
#Getter
#JsonProperty("_embedded")
private Events events;
#Data
public static class Venue {
#JsonProperty("name")
public String name;
}
#Data
public static class Classification {
#JsonProperty("name")
public String name;
}
#Data
public static class Embedded2 {
#JsonProperty("venues")
public List<Venue> venues;
}
#Data
public static class Dates {
#JsonProperty("start")
public Start start;
#JsonProperty("classifications")
public List<Classification> classifications;
#JsonProperty("_embedded")
public Embedded2 _embedded;
}
#Data
public static class EventDetails {
#JsonProperty("name")
public String name;
#JsonProperty("dates")
public Dates dates;
}
#Data
public static class Events {
#JsonProperty("events")
public List<EventDetails> eventsList;
}
#Data
public static class Start {
#JsonProperty("dateTime")
public Date dateTime;
}
}
public class TestJson {
public static void main(String[] args) {
List<EventList.EventDetails> anyCity = findEventByCity("any city");
anyCity.stream().forEach(p-> {
System.out.println(p);
});
}
#SneakyThrows
static List<EventList.EventDetails> findEventByCity(String city) {
ObjectMapper objectMapper = new ObjectMapper();
EventList eventList = objectMapper.readValue(new File("C:\\Anurag\\Development\\CodeBase\\demo\\src\\main\\java\\com\\example\\demo\\domain\\testJson\\test.json"), EventList.class);
List<EventList.EventDetails> eventsList = eventList.getEvents().getEventsList();
return eventsList;
}
}
Related
I have a nested java map like this
inputMap: {jobId={EndpointReference={ReferenceParameters={ResourceURI=http://schemas.com/wbem/wscim/1/cim-schema/2/Job, SelectorSet={Selector=[JID_502260561923, root/im]}}, Address=http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous}}, returncode=4096, messageId=null, arguments=null, message=null}
which I want to map to java pojo and here is my pojo classes.
#Getter
#Setter
#ToString
public class DMResponseMapper {
#Getter
#Setter
#ToString
public static class GetSysConfigDMResponseMapper {
#JsonProperty("jobId")
private EndpointReferenceMapper endpointReferenceMapper;
private Integer returnCode;
private String messageId;
private String arguments;
private String message;
#Getter
#Setter
#ToString
public static class EndpointReferenceMapper {
#JsonProperty("ReferenceParameters")
private ReferenceParametersMapper referenceParametersMapper;
#JsonProperty("Address")
private String address;
#Getter
#Setter
#ToString
public static class ReferenceParametersMapper {
#JsonProperty("ResourceURI")
private String resourceURI;
#JsonProperty("SelectorSet")
private SelectorSetMapper selectorSetMapper;
#Getter
#Setter
#ToString
public static class SelectorSetMapper {
#JsonProperty("Selector")
private List<String> selector;
}
}
}
}
}
but objectMapper.convertValue(inputMap, GetSysConfigDMResponseMapper.class) is NOT mapping the nested classes.. just the top level fields.
My objectMapper is instantiated like this:
static {
objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
Response Object is :
DMResponseMapper.GetSysConfigDMResponseMapper(endpointReferenceMapper=DMResponseMapper.GetSysConfigDMResponseMapper.EndpointReferenceMapper(referenceParametersMapper=null, address=null), returnCode=4096, messageId=null, arguments=null, message=null)
Can anyone please suggest, what is wrong here?
Upon debugging this is what I see:
Converted endpointReferenceMapper to type Object.
DMResponseMapper.GetSysConfigDMResponseMapper(endpointReferenceMapper={EndpointReference={ReferenceParameters={ResourceURI=http://schemas.com/wbem/wscim/1/cim-schema/2/Job, SelectorSet={Selector=[JID_502318722705, root/dcim]}}, Address=http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous}}, returnCode=4096, messageId=null, arguments=null, message=null)
The DMResponseMapper pojo needs to follow the structure of your source data more closely.
Your source Map object has the following structure, based on the info in the question:
inputMap:
{
jobId={
EndpointReference={
ReferenceParameters={
ResourceURI=http://schemas.com/wbem/wscim/1/cim-schema/2/Job,
SelectorSet={
Selector=[JID_502260561923, root/im]
}
},
Address=http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
}
},
returncode=4096,
messageId=null,
arguments=null,
message=null
}
So, I adapted your DMResponseMapper pojo class to more closely map to that structure - and I changed the nested class names as well. Here is a summary of the nested classes with their fields for your data:
//
// NOT the actual class - just an overview of the structure!
//
class DMResponseMapper {
private JobId jobId;
private Integer returncode;
private Object messageId;
private Object arguments;
private Object message;
class JobId {
private EndpointReference endpointReference;
class EndpointReference {
private ReferenceParameters referenceParameters;
private String address;
class ReferenceParameters {
private String resourceURI;
private SelectorSet selectorSet;
class SelectorSet {
private List<String> selector = null;
}
}
}
}
}
This gave me the following, when fleshed out with annotations and getters/setters:
//
// Here is the actual class, based on the above structure.
//
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class DMResponseMapper {
#JsonProperty("jobId")
private JobId jobId;
#JsonProperty("returncode")
private Integer returncode;
#JsonProperty("messageId")
private Object messageId;
#JsonProperty("arguments")
private Object arguments;
#JsonProperty("message")
private Object message;
#JsonProperty("jobId")
public JobId getJobId() {
return jobId;
}
#JsonProperty("jobId")
public void setJobId(JobId jobId) {
this.jobId = jobId;
}
#JsonProperty("returncode")
public Integer getReturncode() {
return returncode;
}
#JsonProperty("returncode")
public void setReturncode(Integer returncode) {
this.returncode = returncode;
}
#JsonProperty("messageId")
public Object getMessageId() {
return messageId;
}
#JsonProperty("messageId")
public void setMessageId(Object messageId) {
this.messageId = messageId;
}
#JsonProperty("arguments")
public Object getArguments() {
return arguments;
}
#JsonProperty("arguments")
public void setArguments(Object arguments) {
this.arguments = arguments;
}
#JsonProperty("message")
public Object getMessage() {
return message;
}
#JsonProperty("message")
public void setMessage(Object message) {
this.message = message;
}
public static class JobId {
#JsonProperty("EndpointReference")
private EndpointReference endpointReference;
#JsonProperty("EndpointReference")
public EndpointReference getEndpointReference() {
return endpointReference;
}
#JsonProperty("EndpointReference")
public void setEndpointReference(EndpointReference endpointReference) {
this.endpointReference = endpointReference;
}
public static class EndpointReference {
#JsonProperty("ReferenceParameters")
private ReferenceParameters referenceParameters;
#JsonProperty("Address")
private String address;
#JsonProperty("ReferenceParameters")
public ReferenceParameters getReferenceParameters() {
return referenceParameters;
}
#JsonProperty("ReferenceParameters")
public void setReferenceParameters(ReferenceParameters referenceParameters) {
this.referenceParameters = referenceParameters;
}
#JsonProperty("Address")
public String getAddress() {
return address;
}
#JsonProperty("Address")
public void setAddress(String address) {
this.address = address;
}
public static class ReferenceParameters {
#JsonProperty("ResourceURI")
private String resourceURI;
#JsonProperty("SelectorSet")
private SelectorSet selectorSet;
#JsonProperty("ResourceURI")
public String getResourceURI() {
return resourceURI;
}
#JsonProperty("ResourceURI")
public void setResourceURI(String resourceURI) {
this.resourceURI = resourceURI;
}
#JsonProperty("SelectorSet")
public SelectorSet getSelectorSet() {
return selectorSet;
}
#JsonProperty("SelectorSet")
public void setSelectorSet(SelectorSet selectorSet) {
this.selectorSet = selectorSet;
}
public static class SelectorSet {
#JsonProperty("Selector")
private List<String> selector = null;
#JsonProperty("Selector")
public List<String> getSelector() {
return selector;
}
#JsonProperty("Selector")
public void setSelector(List<String> selector) {
this.selector = selector;
}
}
}
}
}
}
This is invoked as follows:
First, some test data:
List<String> selector = new ArrayList();
selector.add("JID_502260561923");
selector.add("root/im");
Map<String, Object> selectorSet = new HashMap();
selectorSet.put("Selector", selector);
String resourceURI = "http://schemas.com/wbem/wscim/1/cim-schema/2/Job";
Map<String, Object> referenceParameters = new HashMap();
referenceParameters.put("ResourceURI", resourceURI);
referenceParameters.put("SelectorSet", selectorSet);
String address = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
Map<String, Object> endpointReference = new HashMap();
endpointReference.put("ReferenceParameters", referenceParameters);
endpointReference.put("Address", address);
Map<String, Object> jobId = new HashMap();
jobId.put("EndpointReference", endpointReference);
Map<String, Object> inputMap = new HashMap();
inputMap.put("jobId", jobId);
inputMap.put("returncode", 4096);
inputMap.put("messageId", "foo");
inputMap.put("arguments", "bar");
inputMap.put("message", "baz");
Note I replaced your null values with strings, for testing and demonstration.
Then the code to perform the mapping:
ObjectMapper objectMapper = new ObjectMapper();
DMResponseMapper mapper = objectMapper.convertValue(inputMap, DMResponseMapper.class);
The resulting mapper object contains the test data:
I am new to modelmapper. I have Department and Staff classes in my SpringBoot project. Department class has list of staffs. Using ModelMapper I want to create DepartmentDTO that has staffCount field. I have added Department and DepartmentDTO classes below. How to achive this mapping?
Department class
public class Department {
private Long id;
private String departmentName;
private Set<Staff> staffList = new HashSet<>();
public Department(String departmentName) {
super();
this.departmentName = departmentName;
}
// getters and setters
}
DepartmentDTO class
public class DepartmentDTO {
private Long id;
private String departmentName;
private int staffCount = 0;
public DepartmentDTO(String departmentName) {
this.departmentName = departmentName;
}
// getters and setters
}
I have found solution from this post. I have created DepartmentStaffListToStaffCountConverter class. And used it when adding mappings to modelmapper instance on SpringBootApplication configuration file.
DepartmentStaffListToStaffCountConverter
public class DepartmentStaffListToStaffCountConverter extends AbstractConverter<Set<Staff>, Integer> {
#Override
protected Integer convert(Set<Staff> staffList) {
if(staffList != null) {
return staffList.size();
} else {
return 0;
}
}
}
SpringBootApplication file
#SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplication.class, args);
}
#Bean
public ModelMapper getModelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
modelMapper.typeMap(Department.class, DepartmentDTO.class)
.addMappings(new PropertyMap<Department, DepartmentDTO>() {
#Override
protected void configure() {
using(new DepartmentStaffListToStaffCountConverter()).map(source.getStaffList(), destination.getStaffCount());
}
});
return modelMapper;
}
}
I have document with "_id" : ObjectId("5449567cdf97f277c50d1ce2") but I am getting null when trying to get it by id using findOne. How to solve it?
main
public class MongoDBJDBC {
public static void main( String args[] ){
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
ProductService productService = context.getBean(ProductService.class);
Product product = productService.get("5449567cdf97f277c50d1ce2"); // null here
}
}
service
#Service
public class ProductService {
#Autowired
private ProductDao productDao;
#Autowired
private ProductPropertiesDao productPropertiesDao;
public void add(Product product) {
productDao.save(product);
}
public void update(Product product) {
productDao.save(product);
}
public Product get(String id) {
return productDao.get(id);
}
dao
#Repository
public class ProductDao {
#Autowired
private MongoOperations mongoOperations;
public Product get(String id) {
return mongoOperations.findOne(Query.query(Criteria.where("id").is(new ObjectId(id))), Product.class);
}
}
entity
#Document(collection = Product.COLLECTION_NAME)
public class Product implements Serializable {
public Product() {
}
public static final String COLLECTION_NAME = "product";
#Id
private String _id;
private String name;
}
document
{
"_id" : ObjectId("5449567cdf97f277c50d1ce2"),
"name" : "product"
}
MongoDB adds underline prefix before ID field, so you should use Criteria.where("_id"). instead of just id.
I'm new to Java and Jackson and a lot of other technologies which I try to use, so I'd appreciate a detailed answer.
Is there a way to prevent one or more fields from being serialized using Jackson into a JSON String_like format, but without using any kind of JSON annotations?
Something like: mapper.getSerializationConfig().something(ignore("displayname")) if you know what I mean.
My object is an instance of a class that extends another one, and implements one interface also so on, so the fields come from an hierarchy of classes.
I need the JSON representation for that object but containing only certain fields, so I can send that JSON in a mock request through a POST method.
I'm using Jackson 2.2.2.
If you can't change your classes you can create new abstract class/interface with methods with #JsonIgnore annotation. In this class/interface you can define methods which ObjectMapper should skip during serialization/deserialization process.
Please, see below example:
import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws IOException {
Person person = new Person();
person.setId(1L);
person.setName("Max");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(Person.class, PersonMixIn.class);
System.out.println(objectMapper.writeValueAsString(person));
}
}
abstract class Entity {
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
interface Namamble {
String getName();
}
class Person extends Entity implements Namamble {
private String name;
#Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
interface PersonMixIn {
#JsonIgnore
String getName();
}
EDIT - answer for the comments
You can create such mixin interface:
public static interface UserInformationMixIn {
#JsonIgnore
String getField3();
}
and configure ObjectMapper in this way:
objectMapper.addMixInAnnotations(UserInformation.class, UserInformationMixIn.class);
In version 2.5 method addMixInAnnotations was deprecated and addMixIn should be used:
objectMapper.addMixIn(UserInformation.class, UserInformationMixIn.class);
Full example source code:
import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws IOException {
UserInformation userInformation = new UserInformation();
userInformation.setField3("field3");
userInformation.setField4("field4");
userInformation.setField5("field5");
User user = new User();
user.setField1(userInformation);
user.setField2("field2");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(UserInformation.class, UserInformationMixIn.class);
objectMapper.addMixIn(User.class, UserInformationMixIn.class);
System.out.println(objectMapper.writeValueAsString(user));
}
public static abstract class Someclass {
String field5;
public String getField5() {
return field5;
}
public void setField5(String field5) {
this.field5 = field5;
}
}
public static class UserInformation extends Someclass {
String field3;
String field4;
public String getField3() {
return field3;
}
public void setField3(String field3) {
this.field3 = field3;
}
public String getField4() {
return field4;
}
public void setField4(String field4) {
this.field4 = field4;
}
}
public static class User {
UserInformation field1;
String field2;
public UserInformation getField1() {
return field1;
}
public void setField1(UserInformation field1) {
this.field1 = field1;
}
public String getField2() {
return field2;
}
public void setField2(String field2) {
this.field2 = field2;
}
}
public static interface UserInformationMixIn {
#JsonIgnore
String getField3();
#JsonIgnore
String getField2();
#JsonIgnore
String getField5();
}
}
Helpful link:
How can I tell jackson to ignore a property for which I don't have
control over the source code?
I am having trouble with this json.
{"directory": {
"employees": {"employee": [
{
"field": [
{
"content": "Charlotte Abbott",
"id": "displayName"
},
{
"content": "Charlotte",
"id": "firstName"
},
I am casting it into a class that looks like this
#SerializedName("directory")
public Directory directory;
public class Directory
{
#SerializedName("employees")
public Employees employees;
}
public class Employees
{
#SerializedName("employee")
public List<Employee> employee;
}
public class Employee
{
#SerializedName("field")
public List<Fields> fields;
#SerializedName("id")
public String employeeId;
}
public class Fields
{
#SerializedName("content")
public String content;
#SerializedName("id")
public String label;
}
And it is not reaching all the variables to insert the data when it serializes. Instead I am getting all nulls. I am however getting the right amount (number) of Directory objects so I know it is reaching that far. Anyone have some insight on what I am doing wrong here? The json is the way it is, I didn't design it, but it is how it is used.
Quite a weird data structure you have to work with, but here is it.
public class App {
public static void main(String[] args) {
Gson gson = new Gson();
String jsonString = "{\"directory\": {\"employees\": {\"employee\": [{\"field\": [{\"content\": \"Charlotte Abbott\",\"id\": \"displayName\"},{\"content\": \"Charlotte\",\"id\": \"firstName\"}]}]}}}";
Wrapper obj = (Wrapper) gson.fromJson(jsonString, Wrapper.class);
System.out.println(obj.getDirectory().getEmployees().getEmployeeList()
.get(0).getFieldList().get(0).getContent());
}
}
You need a Wrapper class to wrap around Directory.
public class Wrapper {
private Directory directory;
public Directory getDirectory() {
return directory;
}
public void setDirectory(Directory directory) {
this.directory = directory;
}
}
Directory class.
public class Directory {
#SerializedName("employees")
private Employees employees;
public Employees getEmployees() {
return employees;
}
public void setEmployees(Employees employees) {
this.employees = employees;
}
}
Employees class:
public class Employees {
#SerializedName("employee")
private List<Employee> employeeList;
public List<Employee> getEmployeeList() {
return employeeList;
}
public void setEmployeeList(List<Employee> employeeList) {
this.employeeList = employeeList;
}
}
Employee class:
public class Employee {
#SerializedName("field")
private List<Field> fieldList;
public List<Field> getFieldList() {
return fieldList;
}
public void setFieldList(List<Field> fieldList) {
this.fieldList = fieldList;
}
}
Field class:
public class Field {
#SerializedName("content")
private String content;
#SerializedName("id")
private String id;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
See a JSON to Java Object using GSON example here: http://java.sg/parsing-a-json-string-into-an-object-with-gson-easily/
So here is how it worked out, i had it right, i just wasn't validating the data correctly after it was being put in, and so I was losing it by not being able to assign it and store it for later access.
It is ugly but the map looks like this
DIRECTORY obj
{
EMPLOYEES obj
{
List employee []
{
int id
List fields[]
{
content
id
{
{
{
{