Converting javascript key value pair object to a java key value pair. - java

I have a javascript array containing an object which represents a key value pair. I'm trying to convert this javascript object into a java object. Could someone assist me? Thanks in advance.
Javascript
var array = [];
for (var i = 0; i < filterIdArray.length; i++) {
array.push({name:filterIdArray[i], value:$("#" + filterIdArray[i]).val()});
}
params["t:array"] = array;
Java
#RequestParameter(value = "t:array", allowBlank = true) String array
List<String> inputs = null;
if(array != null) {
inputs = Arrays.asList(array);
}
Java Object representing key value pair
public class Test {
private String name;
private String value;
public Test() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

Related

Java Reflection traverse into nested object and list and update the fields

I have the following complex POJO class Invoice
public class Measure {
private String id;
private Float value;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public Float getValue() { return value; }
public void setValue(Float value) { this.value = value; }
}
public class LineItem {
private Integer lineNumber;
private Measure shipped;
private List<LineItem> lineItems;
public Integer getLineNumber() { return lineNumber; }
public void setLineNumber(Integer lineNumber) { this.lineNumber = lineNumber; }
public Measure getShipped() { return shipped; }
public void setShipped(Measure shipped) { this.shipped = shipped; }
public List<LineItem> getLineItems() { return lineItems; }
public void setLineItems(List<LineItem> lineItems) { this.lineItems = lineItems; }
}
public class Invoice {
private String originUid;
private String vehicleUid;
private List<LineItem> lineItems;
public String getOriginUid() { return originUid; }
public void setOriginUid(String originUid) { this.originUid = originUid; }
public String getVehicleUid() { return vehicleUid; }
public void setVehicleUid(String vehicleUid) { this.vehicleUid = vehicleUid; }
public List<LineItem> getLineItems() { return lineItems; }
public void setLineItems(List<LineItem> lineItems) { this.lineItems = lineItems; }
}
Now I want to traverse deep into every single field including nested objects in the Invoice object and update them using Reflection.
I can call updateIncomingObject() recursively. But I need to know how to get the nested objects out of the field as shown in the commented section.
public Object updateIncomingObject(Object incomingObject) {
Field[] incoming = incomingObject.getClass().getDeclaredFields();
for (Field incomingField : incoming) {
incomingField.setAccessible(true);
if (incomingField.getType().isArray()) {
// for (each occurrence in thisArray ???) {
// Object result = updateIncomingObject(occurrence);
// thisArray.set(index,result);
// }
// incomingField.set(incomingObject, thisArray);
}
else if (!incomingField.getType().getName().startsWith("java.lang")) {
// Object objInstance = incomingField.???;
// Object result = updateIncomingObject(objInstance);
// incomingField.set(incomingObject, result);
}
else {
if (incomingField.getType().equals(String.class) && incomingField.get(incomingObject) != null) {
String trimmed = incomingField.get(incomingObject).toString().trim();
incomingField.set(incomingObject, trimmed);
}
}
}
return incomingObject;
}
How do I turn field into object instance?
To access the objects of an array (fields defined with []) you can do the following:
if (incomingField.getType().isArray()) {
Object[] thisArray = (Object[]) incomingField.get(incomingObject);
for (int k = 0; k < thisArray.length; k++) {
Object occurrence = thisArray[k];
Object result = updateIncomingObject(occurrence);
thisArray[k] = result;
}
incomingField.set(incomingObject, thisArray);
}
To access the objects of a List you can do the following:
if (List.class.isAssignableFrom(incomingField.getType())) {
List<?> thisList = (List<?>) incomingField.get(incomingObject);
for (int k = 0; k < thisList.size(); k++) {
Object occurrence = thisList.get(k);
Object result = updateIncomingObject(occurrence);
thisList.set(k, occurrence);
}
}
Note: If you call updateIncomingObject when iterating on arrays/lists and the object in the array/list is an array (Object[]) your method won't do anything, because the number of declared fields for an array (Object[]) class is 0.
I hope this helps you.

Iterate over heterogeneous list

I have a method which returns the list like
public List<Object> getSomeData(SomeBean sb) {
List<Object> data = Lists.newArrayList();
data.add(sb.getId()); // Id->long
data.add(sb.getName()); // name->String
.....
return data;
}
and Now I have to iterate over this list, which I have to check type every time as
for (int i = 0; i < data.size(); i++) {
if (data.get(i) instanceof String) {
//append
}
if (data.get(i) instanceof Long) {
//append
}
....
}
I need to append the elements of list in the loop.
Are their any better way to achieve this, may be without using instanceof operator.
You should create a class for that data and return an instance of it instead of a List.
class SomeEntity {
long id;
String name;
public SomeEntity(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
#Overrides
public String toString() {
return id + " " + name;
}
}
Just use it in your code:
public SomeEntity getSomeData(SomeBean sb) {
SomeEntity entity = new SomeEntity(sb.getId(), sb.getName());
return entity;
}
Edit: you can override the toString() method of the class and use it in your code (added above)
Here you go:
final List<Object> someData = new ArrayList<>();
someData.add("stringValue"); //String
someData.add(1L); //Long Value
final String result = someData.stream()
.map(String::valueOf)
.collect(Collectors.joining(" "));
System.out.println(result);

Jackson Can not deserialize empty array

Im reading the Facebook Insights and trying to get Jackson to map the JSON to Object. If all the data comes in without empty, i have it working. But Im having a problem trying to deserialize empty array of key value. Even after trying this post: How to prevent null values inside a Map and null fields inside a bean from getting serialized through Jackson it did not resolve the problem :(
This is the JSON :
{"data":[{"id":"492640667465465\/insights\/page_fans_country\/lifetime","name":"page_fans_country","period":"lifetime","values":[{"value":{"MY":26315,"ID":311,"SG":77,"NP":63,"MM":56,"PH":51,"GB":44,"US":44,"KR":36,"TH":36,"IN":34,"BD":24,"PK":22,"BN":22,"AU":15,"TW":14,"VN":12,"KH":11,"YE":11,"CA":10,"JP":10,"EG":8,"ZA":7,"SA":6,"ES":6,"HK":6,"FR":6,"IT":5,"IL":5,"IR":5,"NG":5,"LK":5,"BR":5,"IQ":4,"AF":4,"AE":4,"GT":4,"RO":4,"LR":4,"RU":4,"PS":4,"DE":4,"CN":4,"LY":3,"JO":3},"end_time":"2014-08-02T07:00:00+0000"},{"value":{"MY":26326,"ID":315,"SG":77,"NP":63,"MM":56,"PH":54,"GB":44,"US":43,"TH":38,"KR":36,"IN":33,"BD":23,"BN":22,"PK":21,"AU":16,"TW":14,"VN":12,"KH":11,"YE":11,"CA":10,"JP":10,"EG":8,"ZA":7,"SA":7,"ES":6,"HK":6,"FR":6,"IT":5,"IL":5,"IR":5,"NG":5,"LK":5,"BR":5,"IQ":4,"RU":4,"CN":4,"GT":4,"RO":4,"LR":4,"AF":4,"PS":4,"DE":4,"AE":4,"LY":3,"CH":3},"end_time":"2014-08-03T07:00:00+0000"},{"value":{"MY":26338,"ID":312,"SG":79,"NP":63,"MM":55,"PH":52,"US":45,"GB":44,"TH":39,"KR":34,"IN":32,"BD":24,"BN":22,"PK":21,"AU":16,"TW":14,"KH":12,"VN":12,"CA":11,"YE":11,"JP":10,"EG":8,"ZA":7,"SA":7,"ES":6,"HK":6,"FR":6,"IT":5,"CN":5,"IR":5,"NG":5,"LK":5,"BR":5,"IL":5,"IQ":4,"AF":4,"AE":4,"GT":4,"RO":4,"LR":4,"RU":4,"PS":4,"DE":4,"NZ":3,"TR":3},"end_time":"2014-08-04T07:00:00+0000"}],"title":"Lifetime Likes by Country","description":"Lifetime: Aggregated Facebook location data, sorted by country, about the people who like your Page. (Unique Users)"},{"id":"492640667465465\/insights\/page_storytellers_by_country\/day","name":"page_storytellers_by_country","period":"day","values":[{"value":[],"end_time":"2014-08-02T07:00:00+0000"},{"value":[],"end_time":"2014-08-03T07:00:00+0000"},{"value":[],"end_time":"2014-08-04T07:00:00+0000"}],"title":"Daily Country: People Talking About This","description":"Daily: The number of People Talking About the Page by user country (Unique Users)"},{"id":"492640667465465\/insights\/page_storytellers_by_country\/week","name":"page_storytellers_by_country","period":"week","values":[{"value":{"MY":136,"IN":3,"ID":2,"BD":1,"US":1,"TN":1,"AU":1},"end_time":"2014-08-02T07:00:00+0000"},{"value":{"MY":131,"IN":3,"US":1,"TN":1,"AU":1,"ID":1},"end_time":"2014-08-03T07:00:00+0000"},{"value":{"MY":118,"IN":2,"KH":1,"TR":1,"US":1,"TN":1,"AR":1,"AU":1},"end_time":"2014-08-04T07:00:00+0000"}],"title":"Weekly Country: People Talking About This","description":"Weekly: The number of People Talking About the Page by user country (Unique Users)"},{"id":"492640667465465\/insights\/page_storytellers_by_country\/days_28","name":"page_storytellers_by_country","period":"days_28","values":[{"value":{"MY":492,"IN":5,"ID":3,"AU":2,"SG":2,"ZA":2,"US":2,"GB":2,"RO":1,"PH":1,"NP":1,"BD":1,"JO":1,"PS":1,"TN":1,"IR":1,"CA":1,"CN":1,"KR":1},"end_time":"2014-08-02T07:00:00+0000"},{"value":{"MY":499,"IN":5,"ID":3,"GB":2,"SG":2,"ZA":2,"US":2,"RO":1,"PH":1,"NP":1,"BD":1,"AU":1,"CN":1,"KR":1,"TN":1,"IR":1,"CA":1,"JO":1},"end_time":"2014-08-03T07:00:00+0000"},{"value":{"MY":501,"IN":4,"ID":3,"SG":2,"ZA":2,"US":2,"GB":2,"AU":1,"RO":1,"PH":1,"NP":1,"JO":1,"AR":1,"KR":1,"BD":1,"TR":1,"IR":1,"CA":1,"CN":1,"KH":1,"TN":1},"end_time":"2014-08-04T07:00:00+0000"}],"title":"28 Days Country: People Talking About This","description":"28 Days: The number of People Talking About the Page by user country (Unique Users)"}],"paging":{"previous":"https:\/\/graph.facebook.com\/v2.0\/492640667465465\/insights?since=1406649169&until=1406908369","next":"https:\/\/graph.facebook.com\/v2.0\/492640667465465\/insights?since=1407167569&until=1407426769"}}
My current code does not like this at all --> "value":[]
And the follwing is my Object:
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
public class Insights {
private Data[] data;
private Paging paging;
public Data[] getData() {
return data;
}
public void setData(Data[] data) {
this.data = data;
}
public Paging getPaging() {
return paging;
}
public void setPaging(Paging paging) {
this.paging = paging;
}
/**
* inner class for Data
* #author pohsoon.yap
*
*/
public static class Data {
private String id;
private String name;
private String period;
private Values[] values;
private String title;
private String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPeriod() {
return period;
}
public void setPeriod(String period) {
this.period = period;
}
public Values[] getValues() {
return values;
}
public void setValues(Values[] values) {
this.values = values;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
/**
* inner class for Values
* #author pohsoon.yap
*
*/
public static class Values {
// if "value":[] then this will break
private Map<String, Integer> Value;
private String end_time;
public Map<String, Integer> getValue() {
return Value;
}
public void setValue(Map<String, Integer> value) {
Value = value;
}
public String getEnd_time() {
return end_time;
}
public void setEnd_time(String end_time) {
this.end_time = end_time;
}
}
}
public static class Paging {
private String previous;
private String next;
public String getPrevious() {
return previous;
}
public void setPrevious(String previous) {
this.previous = previous;
}
public String getNext() {
return next;
}
public void setNext(String next) {
this.next = next;
}
}
}
My code snippet as follows:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
List<Insights> insightList = new ArrayList();
String insightStr = "";
try {
for (Operation operation : mq.getOperationList()){
String apiEndPoint = this.facebookGraphApiUrl + operation.getApi();
apiEndPoint = apiEndPoint.replace("{pageid}", mq.getFacebookPage().getPageId());
uri = new URI(apiEndPoint);
insightStr = facebook.getApi().restOperations().getForObject(uri, String.class);
Insights insights = mapper.readValue(insightStr, Insights.class);
The full stack trace:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token
at [Source: java.io.StringReader#625a80df; line: 1, column: 1603] (through reference chain: com.social.facebook.model.Insights["data"]->com.social.facebook.model.Data["values"]->com.social.facebook.model.Values["value"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:599)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:593)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:306)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:147)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:147)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2796)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1942)
As explained by others, you are trying to map JSON Array into Java Map, something that is not allowed by default.
But it may be possible to allow empty JSON Array to map to java.util.Map. by enabling DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT:
objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);
this at least works in case of a POJO type; I do not recall if this works for other Java types that usually take JSON Object.
The value field in your model is declared as Map while the corresponding JSON property can be either an empty array or a key-value map. Jackson cannot assign an empty array to a map field.
Assuming that you wish to solve the problem on the client side, you can modify the setValue method to accept a generic Object and then verify whether it is a map or an array (actually List since Jackson deserialize arrays as Java collections). Here is an example:
public class JacksonArrayAsMap {
public static class Bean {
private Map<String, Object> value;
public void setValue(Object value) {
if (value instanceof Map) {
this.value = (Map<String, Object>) value;
} else if (value instanceof List && ((List) value).size() == 0){
this.value = Collections.EMPTY_MAP;
} else {
throw new IllegalArgumentException("Invalid value: " + value);
}
}
#Override
public String toString() {
return "Bean{" +
"value=" + value +
'}';
}
}
public static void main(String[] args) throws IOException {
final String json1 = "{\"value\":{}}";
final String json2 = "{\"value\":[]}";
final String json3 = "{\"value\":{\"a\":\"b\"}}";
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json1, Bean.class));
System.out.println(mapper.readValue(json2, Bean.class));
System.out.println(mapper.readValue(json3, Bean.class));
}
}
Output:
Bean{value={}}
Bean{value={}}
Bean{value={a=b}}

Java-Collections, cannot overwrite old value with new value

I got a question regarding Java-Collections. I iterate through a Java-Collection and if an if-clause is true, I want to change the entry of the Collection. Within the if-clause body the new Value is accepted, but if I want to print the whole collection later, it prints out again the Collection with the old value.
Here the Code:
public boolean checkConsumeStorageCapacity(Multimap<String, Values> mm1, Multimap<String, Values> mm2)
{
boolean enoughStorageCapacity = false;
Multimap<String, Values> mmApp = mm1;
Multimap<String, Values> mmHW = mm2;
Collection<Values> colA = mmApp.get("Storage");
Collection<Values> colH = mmHW.get("Memory");
for (Values vA2 : colA) {
for (Values vH2 : colH) {
if (vA2.getName().equals("Size") && vH2.getName().equals("Size")) {
float StoSize = Float.parseFloat(vA2.getValue());
float MemSize = Float.parseFloat(vH2.getValue());
float maintainableStoSize = StoSize * maintainabilityfactor;
if (MemSize >= maintainableStoSize) {
MemSize -= maintainableStoSize;
vH2.setValue(String.valueOf(MemSize));
String s = vH2.getValue();
System.out.println(s);
enoughStorageCapacity = true;
return enoughStorageCapacity;
}
break;
}
}
}
System.out.println(colH);
Values is a object containing 3 String. The getters/setters are all declared correctly. Printing out s gives the correct value, but printing out colH gives again the old value. Isnt setting the new Value enough, do I additionally have to commit anything in the Collection?
Thanks a lot in advance.
edit:
here the values class, for further understanding.
public class Values {
private String name;
private String type;
private String value;
public Values(String name, String type, String value)
{
this.name = name;
this.type = type;
this.value = value;
}
public String getName()
{
return name;
}
public String getType()
{
return type;
}
public String getValue()
{
return value;
}
public void setName(String name)
{
this.name = name;
}
public void setValue(String value)
{
this.value = value;
}
public void setType(String type)
{
this.type = type;
}
#Override
public String toString() {
return "name=" + name + ", type=" + type + ", value=" + value;
}
}
Another way of dealing with such pointer issues is to initialize a second collection before the loop. As you iterate through add the values that you want to stay the same to the collection and then in the if statement add the changed value/object. This costs a little more memory but no real performance loss
Something like this:
list<T> originallist;
list<T> tmp = new list
for(x : originalList)
{
if(condition)
{
//do things
tmp.add(changedValue)
}
else
{
tmp.add(x)
}
}

Java enum: get FieldName knowing its value

public enum Code {
E1330("MERCOSUR (SOUTH AMERICAN COMMON MARKET)"),
E0257("Guinea Biss."),
E0252("Gambia");
private Code(String value){
setStringValue(value);
}
private Code (int value) {
setIntValue(value);
}
private int intValue;
private String stringValue;
public String getStringValue() {
return stringValue;
}
public int getIntValue() {
return intValue;
}
public void setStringValue(String value) {
this.stringValue = value;
}
public void setIntValue(int value) {
this.intValue = value;
}
}
How can I get the field name of the Code whose value is "Gambia"?
-> it would be E0252
Thank you
You can search for it via a loop:
String val = "Gambia";
String field = "";
for (Code c : Code.values())
if (c.getStringValue().equals(val)) {
field = c.name();
break;
}
System.out.println(field);
Output:
E0252

Categories

Resources