I have a class defined as below:
// Ignore all the unknown properties in input JSON
#JsonIgnoreProperties(ignoreUnknown = true)
// Only include non null values in deserialized Java object.
#JsonInclude(value = Include.NON_NULL)
public class Person {
#JsonProperty("person_id")
private String personId;
#JsonProperty("school")
private String school;
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
public Map<String, List<AttributeBag>> getHobbies() {
return hobbies;
}
public Person(String person_id, String school) {
super();
this.person_id = person_id;
this.school = school;
}
When I use a JSON string below to deserialize from string to object,
{
"person_id":"123",
"school":"stanford University"
}
From the object I got deserialized, the hobbies is create but empty, and the tasks is not created even. I am expecting the way like "tasks", if there is no corresponding field in JSON, it SHOULD NOT get deserialized in the object.
But the weird thing is : when I check object.getHobbies()!=null but the tasks part is null. I want both are null in the object if they were not present in JSON.
I have a constructor for the Person class but I did not initialize both hobbies and tasks part.
Thanks a lot
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
from above code its clear that you are creating new objects for hobbies and tasks no matter what, I am not able to understand why your tasks are not created(it should get created as a empty map)
and to answer your question #JsonInclude(value = Include.NON_NULL) should do the trick!
The JSON deserialiser will not attempt to set the fields that don't appear in the JSON structure, but these lines:
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
are creating the values on object construction.
If you want them to be null then don't allocate them in the object, just leave the declaration:
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies;
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks;
Related
I want to copy fields from a complex object- that is an object which contains other objects.
Now it copies wrapper classes with no issue but how do i copy the fields and values of the subclass
code
public Map<String, Object> getValueMapFromInsuranceVehicle(Long insuranceId) throws InvocationTargetException, IllegalAccessException {
InsurancePolicy insurance = repository.findById(insuranceId).get();
Method[] methods = insurance.getInsuranceVehicle().getClass().getMethods();
Map<String, Object> map = new HashMap<String, Object>();
for (Method m : methods) {
if (m.getName().startsWith("get")) {
Object value = m.invoke(insurance.getInsuranceVehicle());
map.put(m.getName().substring(3), value);
}
}
// add other fields specific to our needs like currentYear
return map;
}
From the code above it copies insuranceVehicle fields correctly, But i would like to copy the whole InsurancePolicy object and put the values in a map.
when i try it with InsurancePolicy i get exception cannot convert InsurancaCalculation into String,
my Insurance policy object looks like this
class InsurancePolicy {
#OneToOne
private Person person;
#OneToOne
private Vehicle vehicle;
#OneToOne
private InsurancePolicyStatus status;
private LocalDate policyStart = LocalDate.now().plusDays(1);
private LocalDate policyEnd = policyStart.plusYears(1).minusDays(1);
private boolean policy_AC = true;
private boolean policy_OC = true;
private boolean policy_ASS;
private boolean policy_NNW;
private String vehicleUsageType;
InsuranceCalculation calculation
#Embedded
private InsuranceVehicle insuranceVehicle;
#Embedded
private InsuranceCustomer customer;
private String coownerHowMany;
private String abroad;
}
Finally my question how can i improve my method getValueMapFromInsuranceVehicle() to get more fields copied ?
basically how to make this code below to work
public Map<String, Object> getValueMapFromInsuranceVehicle(Long insuranceId) throws InvocationTargetException, IllegalAccessException {
InsurancePolicy insurance = repository.findById(insuranceId).get();
Method[] methods = insurance.getClass().getMethods(); // insurance instead of vehicle
Map<String, Object> map = new HashMap<String, Object>();
for (Method m : methods) {
if (m.getName().startsWith("get")) {
Object value = m.invoke(insurance); // insurance instead of insurancevehicle
map.put(m.getName().substring(3), value);
}
}
// add other fields specific to our needs like currentYear
return map;
}
To get the methods of other objects in InsurancePolicy you could use your same code but add some checks for if the object is InsuranceCustomer, InsuranceVehicle, or InsuranceCalculation by using instanceOf and if it is use the same code just with Method[] methods = insurance.getClass().getMethods(); changed to the objects class. I would recommend separating your code into more methods so you can use recursion.
I am trying to create a map from all the attributes that a class have.My class looks like :
public class MyInventory
{
private int tiers = 80;
private int stearing =135;
private int battery = 46;
}
Now I have collected all the methods that the class has as :
Field[] fields = this.getClass().getDeclaredFields();
Now , I am trying to create a Map out of it where keys are the values of the fields and the values are the name of the fields. Example :
Map<46,battery> ...etc
Is there a way to do it?
The attribute values for the above mentioned class were generated by mapping to properties file and by using spring annotation #ConfigurationProperties. Now I need to create the Map but keys the values of the attributes. I tried to use reflect. However did not find a way to get the value of the fields.
Thanks
You can use Introspector class.
public Map<Object, String> populateMap(final Object o) throws Exception {
Map<Object, String> result = new HashMap<>();
for (PropertyDescriptor pd : Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors()) {
String fieldName = pd.getName();
if("class".equals(fieldName) continue;
Object value = pd.getReadMethod().invoke(o);
result.put(value, fieldName);
}
return result;
}
You can call the above method, passing your class as argument.
MyInventory mi = new MyInventory();
// Sets the properties of mi
mi.setXXX...
// Populates map
populateMap(mi);
Map<Integer, String> map() throws IllegalArgumentException, IllegalAccessException {
Field[] fields = getClass().getDeclaredFields();
Map<Integer,String> map = new HashMap<>();
for (Field field : fields) {
map.put(field.getInt(this), field.getName());
}
return map;
}
Of course it will not map properly if different fields have the same value.
I think, you can have getter method in your class
public class MyInventory
{
private int tiers = 80;
private int stearing =135;
private int battery = 46;
public int getBattery()
{
return battery;
}
//and other getter
}
and then you can populate your map as
map.put(inventory.getBattery(),"battery");
Because, when you have value, which means you know what is the type for which you are populating map.
You can use json parser. For example jackson:
import com.fasterxml.jackson.databind.ObjectMapper;
...
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(mapper.writeValueAsString(fooOject), HashMap.class);
Is it possible to convert map into a pojo when attribute names are different?
I am extracting raw input into a map to have the following data. Data can vary based on message type. For example:
for Message type = STANDARD
Map<String, Double> data = new HashMap<>();
data.set('TEMP', 18.33);
data.set('BTNUM', 123);
for Message type = NON_STANDARD
Map<String, Double> data = new HashMap<>();
data.set('GPSLAT', 12.33);
data.set('GPSLON', 42.33);
For each message type I have a Java model class
#Data
public class StandardMessage {
private String longitude;
private String latitude;
}
#Data
public class NonStandardMessage {
private String temperature;
private String btNumber;
}
Currenly I am mapping data to POJO class manually like below
StandardMessage sm = new StandardMessage();
sm.setLongitude(data.get('GPSLON'));
NonStandardMessage nsm = new NonStandardMessage();
nsm.setTemperature(data.get('TEMP'));
Is it possible to make above mapping generic? i.e setting object property without knowing name?
In Typescript we can achieve this easily by defining configuration like:
objectPropertyMapping = new Map();
objectPropertyMapping.set('GPSLAT', 'latitude');
objectPropertyMapping.set('GPSLON', 'longitude');
standardMessage = {};
data.forEach((value: boolean, key: string) => {
standardMessage[ObjectPropertyMapping.get(key)] = data[key];
});
https://stackblitz.com/edit/angular-zjn1kc?file=src%2Fapp%2Fapp.component.ts
I know Java is a statically-typed language, just wondering is there a way to achieve this like typescript or we have to map manually all the time?
We use jackson-databind. It uses annotations for configuration.
Here are some example:
The entity class:
class MessageRequest {
#JsonProperty("A")
private String title;
#JsonProperty("B")
private String body;
... getters and setters ...
}
The main method:
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> source = new HashMap<>();
source.put("A", "This is the title");
source.put("B", "Here is the body");
MessageRequest req = objectMapper.convertValue(source, MessageRequest.class);
System.out.println(req.getTitle());
System.out.println(req.getBody());
}
I've tried so many ways, but without success to parse this Json to a Java Object using Gson library:
"return":{
"48388":{
"status":"canceled",
"operations":{
},
"created":"138232386",
"price":"12.50000",
"volume":"50.00000000",
"pair":"btc_brl",
"type":"buy"
},
"51714":{
"status":"canceled",
"operations":{
},
"created":"1365465421706",
"price":"1500.00000",
"volume":"0.10000000",
"pair":"btc_brl",
"type":"buy"
},
"48754":{
"status":"canceled",
"operations":{
},
"created":"1383237058",
"price":"600.00000",
"volume":"0.50000000",
"pair":"btc_brl",
"type":"buy"
}
"success":1
}
There is a lot of topics about this, but none of them cover this type of json mapping.
I'm convinced that there is a simple way to do that, any ideas? Thanks!
EDIT:
I'm trying this:
public class Test {
#SerializedName("return")
public Return1 _return;
}
public class Return {
public List<Map<String, Order>> order;
}
EDIT:
public class Order {
#SerializedName("id")
private int idOrder;
private String status;
private String created;
private String price;
private String volume;
private String pair;
private String type;
private List<Operations> operations;
// All the gets and sets here..
}
Gson doesn't initialize my order object. The order object is always null. I can't find the correct way to implement this mapping.
After a long battle I was able to solve using this solution:
public void deserialize() {
Gson gson = new Gson();
// For isr read InputStreamReader
Map<String, Object> map = gson.fromJson(isr, Map.class);
System.out.println(map.get("success"));
Map<String, Object> map2 = (Map<String, Object>) map.get("return");
// Show the contents of return
System.out.println(map2);
}
After that I used an Entry object to iterate and set the values of Order.
Thanks!
Here is my problem:
I have list of possible Product categories(for example: Shoes,Mode,Women), and I need to convert this to my specific names.
example: I get the category Women and I need to convert this to Lady's.
I have about 40 category names that i need to convert.
My question is :What is the best way to do this in JAVA.
I thought about switch case, but i dont know is this a good solution.
switch (oldCategoryName) {
case "Women":
return "Ladys";
default:
return "Default";
}
You can use static map for that.
Make a Static Map as below
public class PropertiesUtil {
private static final Map<String, String> myMap;
static {
Map<String, String> aMap = new HashMap<String, String>();
aMap.put("Women", "Ladys");
aMap.put("another", "anotherprop");
myMap = Collections.unmodifiableMap(aMap);
}
}
then get the replacing string..
String womenReplace = PropertiesUtil.myMap.get("Women");
You can also consider using enums:
public enum ProductsCategory {
Mode("MyMode"),
Shoes("MyShoes");
private String name;
private ProductsCategory(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Then the retrieval:
String myModeStr = ProductsCategory.Mode.getName();
Note that the java switch does not work on String objects for java versions below 7.
You can store values in a map :
// storing
Map<String, String> map = new HashMap<String, String>();
map.put("Women", "Ladys");
// add other values
// retrieving
String ladys = map.get("Women");
Or you can also use a .properties file to store all those associations, and retrieve a property object.
InputStream in = new FileInputStream(new File("mapping.properties"));
Properties props = new Properties();
props.load(in);
in.close();
String ladys = props.getProperty("Women");