I want to retrieve a map of field-values present in a java object. I tried com.google.Gson and org.apache.commons.lang3.builder.ToStringBuilder to retrieve all the details regarding the given object. But following problems occured :
com.google.Gson:
Gson gson = new GsonBuilder.create();
String str = gson.reflectionToString(myObject);
StackOverFlowError occurs for some objects, even a map having JSONObject fails miserably.
org.apache.commons.lang3.builder.ToStringBuilder:
String str = ToStringBuilder.reflectionToString(myObject);
While using the above API for HashMap, variables inside the HashMap are displayed but contents of the HashMap are not visible.
Output :
samplePackage.CustomHashMap#5fec459b[accessOrder=false,threshold=12,loadFactor=0.75]
Help me to find the perfect solution !
You could try using reflection. This allows you to use your class name to access your class and its meta data. You can then use the getDeclaredFields method to get all the declared Fields for your class. Your fields can be private this way so they can't be edited by outside classes without calling getters or setters.
//initialize the name of your class.
String className = "examplePackageName.exampleClassName";
//get your class using the name of the class
Class<? extends ObjectImplementation> Classtouse = Class.forName(className);
//initialize map of fieldnames to field objects from reflection
Map<String,Field> FieldMap = new HashMap<>();
//gets delcared fields as a List, converts it to an array and for each element in the
//array, it maps the element's name to the element itself as a field object
Arrays.asList(Classtouse.getDeclaredFields()).forEach(Field -> FieldMap.put(Field.getName(),Field));
//now you have your fieldmap ready to use.
when you want to access the value of a Field, you can use
//instantiate an object of your Class with type Classtouse here
//use the object created in the line above and set its fields using the line
//below
field.get(//Object that holds this field);
Where field is the Field object you want to edit which you accessed using the fieldname or some other method. If you want to map fieldnames to field values directly you can edit this from the code above:
Arrays.asList(Classtouse.getDeclaredFields()).forEach(Field -> FieldMap.put(Field.getName(),Field));
to be:
Arrays.asList(Classtouse.getDeclaredFields()).forEach(Field -> FieldMap.put(Field.getName(),Field.get(//your object here)));
Just make sure you have instantiated an object you want to do this with first.
An example of this and other reflection methods can be found in the Field javadoc
Here:[link]https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Field.html
This code is not garenteed to be perfectly runnable but it's close.
Related
Using this code
Map<String,Object> payloadMap = new HashMap<String,Object>();
payloadMap = (Map<String,Object>) new Gson().fromJson(result, payloadMap.getClass());
, I convert this json:
{
"name":"name1",
"job":"prosecutor",
"department": {
"department_name":"prosecutor's office"
}
}
to the map (map with unlimited number of child maps):
This done well, but now I want to get an access to values of child (nested) maps.
In parent map child maps "wrapped" to Object.
So, I tried to get "wrapped" child maps from the Object-values of parent map.
public void mapRequestNode (Map<String,Object> payloadMap) {
payloadMap.entrySet().forEach(node->this.getDataFromNode(node));
}
As you can see from the above picture, there are no way to use child map "department", which had been "wrapped" to Object. I have an access to Object-methods, but not to the Map-methods (for example, I cant use "value.get("department_name")". I tried cast "(Map<String, Object>)value", but without success...
The "department" name in case above is only for example! I dont know concrete name of json child-objects. There may be unlimited number of names! So I cant use something like this "payloadMap.get("department")"
Following
((Map<String, Object>)payloadMap.get("department")).get("department_name")
should work, dont?
Your variable value is of type Object, which means that the compiler will not know anything else about the variable. Even if the object you retrieve from your json file is a map, as you store it in a Object variable, the compiler will handle it as an Object and not as a Map. That is why you cannot do value.get("department"); : the method get does not exist for the type Object.
You need to cast whatever is stored in value.get("department") as a Map<String, Object> to be able to handle it as a Map.
I have found a special solution.
I convert json to Map<String,Map<String,Object>>.
Not in Map<String,Object>. In this case I can successfully use child-maps of parent dto-map.
But this solution is special (not general) in the meaning that, I can handle in this way json, which consist only of objects.
For example, if I try to get the value of "job" in following example:
{
"job": "prosecutor",
"department": {
"department_name":"prosecutor's office"
}
}
by using Map.Entry<String, Map<String, Object>> payloadNodeEntry.getValue,
I will receive ClassCastException (cant cast String to Map<String, Object> ).
There's a class which some of its fields are user-defined objects. I'm going to:
Get the Primary class' fields and traverse through them to get their values.
1.1 When encountering a field with the type of object, go through this object which has its own fields
Get the values of these nested fields (fields of the object type field)
The problem is at step 2; When I get the fields of the object field, couldn't get their values as I need to pass an object to field.get(object) to indicate which object I want the values of the fields being extracted from, But how can I access the current object of our talking field with the type of object?
Here's the code:
public class PrimaryClass {
String str;
int num;
MyClass cls;
}
PrimaryClass primaryObject = new PrimaryClass();
Field[] primaryObjectFields = primaryObject.getClass().getDeclaredFields();
// ... One of the fields is : MyClass foo.bar.cls
// Assuming stored with name of clsField
Field[] myClassObjectFields = clsField.getType().getDeclaredFields();
for (Field f : myClassObjectFields) {
String fieldValue = f.get(primaryObject /* What to pass here? */);
// !!!! The above line Doesn't work since the primary Object doesn't have access to its child's fields
System.out.println(fieldValue);
}
When I get the first level field (and set it accessible with setAccessible(true)), To get its inner object field I call these:
topLevelField.getClass().getDeclaredField("details");
topLevelField.setAccessible(true);
topLevelField.get(primaryObject);
But couldn't get access to the object field which is instantiated inside the parent object and get this error:
java.lang.IllegalArgumentException: Can not set java.util.List field com.foo.Bar.details to com.foo.Bar
The inner object is a List of objects but could be also non-list objects in some cases.
Here is a cool tutorial that can help you get started.
in general, get returns you an object, and then you can cast it to what ever type you want. also , you can ask the field for its type ,and the do some logic accordingly to the type of the field .
there are also cool methods that is better for you to get familiar with clazz.isAssignableFrom(obj.getClass())
you can read more about it here
I have a JSON String like this -
String jsonString1 = "{\"warning\": \"user_id not found\", \"user_id\": some_user_id}";
or
String jsonString2 = "{\"error\": \"user_id for wrong partition\", \"user_id\": some_user_id, \"partition\": some_partition}";
I am trying to map the above JSON String with the below class. I am using GSON here -
public class ErrorResponseTest {
private String error;
private String user_id;
private String partition;
private String client_id;
// getters or setters
}
Problem Statement:
I want to map warning and error in the above JSON String to error variable in my above class. But currently it is mapping only jsonString2 to error variable..
With the use of below code, I can deserialize jsonString2 and then it shows user_id for wrong partition in error variable. But if I try to deserialize the jsonString1 then it shows null value in error variable..
ErrorResponseTest hello = new Gson().fromJson(jsonString2, ErrorResponseTest.class);
Is it possible to map warning to error variable as well in my above class? Meaning if I am deserializing the jsonString1 with the above class, I want to have user_id not found in the error variable..
Is it possible to do?
You can consider 3 approaches:
take a look at the custom naming strategies, http://bethecoder.com/applications/tutorials/json/google-gson/custom-field-names-strategy.html and go crazy trying to map two serialized names to just one class name.
create two different classes, one for warning and other one for error, and a common parent class with all common fields
change your class and add a 'errorLevel' field. In thr json change 'error' and 'warning' to something like 'message' and add also the 'error_level' field.
I would prefer the third approach, so you only have one class, and the json error message model is more selfcontained, more readable, for say some.
Imagine I have a class called SomeClass which has a list of Strings called aStringList.
public Class SomeClass{
List<String> aStringList;
...
}
I want to find all the objects of SomeClass such that aStringList contains a String "sillyString".
I have tried:
Datastore ds = Dao.instance().getDatabase();
List<String> myResults = ds.find(SomeClass.class).
field("aStringList").hasThisElement("sillyString").asList();
However that gives me the error:
com.mongodb.MongoException: invalid parameter: expected an object ($elemMatch)
Use field(...).equal(...) (assuming you are looking for an exact match). MongoDB will match both single values as well as any value inside an array.
Use .hasThisElement(...) if you have a list of custom document entities (#Reference List<MyEntity>) and you want to check if a specific one is being referenced.
I have an application which makes use of an external library (Jackson), and the method I need requires a class literal as an argument. So if I wish to parse my JSON string into a User object:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("user.json"), User.class);
Now, I wish to use this method dynamically (i.e. parse different JSON strings using the same line of code). For example:
String json1 = "{"type":"jacket",...}";
String json2 = "{"type":"sweater",...}";
Object object = mapper.readValue(json1/json2, ???);
//returns a Jacket object OR Sweater object based on the "type" key
//i.e. use Jacket.class as the 2nd argument if "type" is "jacket"
//OR Sweater.class if "type" is "sweater"
//After getting the deserialized object,
//if object is Jacket, cast as a Jacket
//if object is Sweater, cast as a Sweater
Of course, the JSON string in question can be for any class, so I can't simply hard-code an if-else loop. I've looked at custom serializers, but frankly am quite lost at what it's talking about, and would like some help in how I can go about this.
In summary, I need some way to first define a class literal from a String, and then cast the resulting Object into the specific class (but my focus is on getting readValue to work dynamically).
Looks like you need a mapping somewhere between JSON type variable and Java class type.
Generally result should be something like this map:
Map<String, Class<? extends YourSupertype>> map = new HashMap<>();
map.put("sweater", Sweater.class);
map.put("jacket", Jacket.class);
Just store possible clothing types somewhere in a file, then do something like:
String clothingType = nextEntryFromFile();
String className = constructClassNameFromClothingType(clothingType);
map.put(clothingType, Class.forName(className));
Since version 1.5 Jackson supports Polymorphic Type Handling, check here http://www.cowtowncoder.com/blog/archives/2010/03/entry_372.html
there are examples on how to correctly handle deserialization in those cases.