Deserialize enum into object with string attribute - java

I'm currently trying to deserialize an enum value from a json to an object containing a string(where the enum value should end up).
Example:
Domain class
public class Person {
private UUID personId;
private Occupation occupation;
}
Occupation class:
public class Occupation {
private String occupationType;
}
The code I am running is:
PersonResponse personResponse = JsonConverter.fromJson(message.getPayload(), new TypeReference<Person>() {
});
And the JSON is:
{"personId":"719e622e-6e00-4e84-b748-739f95d7c0fa", "occupationType":"STATE_EMPLOYEE"
Basically, I want my STATE_EMPLOYEE.name() value to end up in a usable object of the Occupation class. As it is now it tries to deserialize the value STATE_EMPLOYEE into an object of the Occupation class, which obviously doesn't work.
Is there a way for me to return an object like this? I don't want to change my Person object to hold an OccupationType enum because it has a load of other stuff as well.
The error I receive is:
Can not construct instance of person.package.Occupation: no String-argument constructor/factory method to deserialize from String value ('STATE_EMPLOYEE')
It basically fails trying to put my enum value into my Occupation object containing the string. (Where I want my thing to be).
Thanks in advance!

I solved it by creating my own custom Deserializer.

Related

Will Gson set a field to null when JSON doesn't contain it?

I actually have multiple questions regarding Gson.
The first one being if Gson would set the value of a field to null when the provided JSON does not contain any field matching it.
For example, when the provided JSON features the field name but the class I deserialize it to contains name and avatar, would avatar be null?
The next question is in relation to the above one. When I would set a field with an already predefined value, would Gson override it, even if it isn't provided in the JSON (overrides it to null) or would it simply ignore the field and move on?
And finally would I want to know if Gson would still set a value to name when I would use #SerializedName("username") but the JSON contains name.
I want to update my API, including some bad namings of JSON fields, but I want to make the transition of it for the people using it a smooth as possible, so I want to still (temporary) provide the old field name, while also providing support for the new one. Is that possible using the #SerializedName annotation?
I'm still a beginner with Gson and the Gson User Guide wasn't that helpful for me to answer those two specific questions (Or I overlooked it which would also be possible).
I tried implementing this. Here is my code. I hope the output at the end answers your question.
JSON used:
{
"name": "Robert",
"weather": "19 deg"
}
Main class:
public class GSONExample2 {
private static final String jsonStr = "JSON Mentioned above";
public static void main(String[] args) {
GsonDataExample root = new Gson().fromJson(jsonStr, GsonDataExample.class);
System.out.println(root);
}
}
POJO:
class GsonDataExample {
#SerializedName("username")
private String name;
private String avatar;
#SerializedName(value="weather", alternate = "temperature")
private String weather;
private String nameWithDefault = "Default name";
// getters, setters and toString() implemented
}
Output:
GsonDataExample(name=null, avatar=null, weather=19 deg, nameWithDefault=Default name)
To map multiple keys to same attributes, you can use #SerializedName(value="weather", alternate = "temperature") as shown above.

Changing json to java pojo

Let's say I have a JSON file example.json
example.json
{
"BaggageMaxSize" : {
"mesurement" : "sum",
"width" : 70,
"height" : 50,
"depth" : 40
}
}
And create the POJO class:
public class pojoexample{
private BaggageMaxSize BaggageMaxSize;
// getter
// setter
}
And then:
public class BaggageMaxSize
{
private String height;
private String width;
private String depth;
private String mesurement;
// getter
// setter
}
Now, I want to use the mapper.readValue to change file to BaggageInfoPolicy.class:
BaggageInfoPolicy bip = mapper.readValue(file, BaggageInfoPolicy.class);
But bip.getBaggageMaxSize().getMesurement() returns null value. Any suggestions?
Try using mapper.writeValue first and check how your resulting JSON object will look like. Very likely, there's an issue with int -> string conversion in your BaggageMaxSize when deserialized from JSON.
Also, check your getters/setters to be publicly visible and be available both on pojoexample and BaggageMaxSize.
Actually your JSON represents a pojoexample class instance and not a BaggageInfoPolicy object, which you haven't shared in your post.
So you need to change your code to:
PojoExample bip = mapper.readValue(file, PojoExample.class);
So it reads the PojoExample object correctly.
Note:
Your class should follow the java naming convention and
start with an uppercase, that's why I changed it to PojoExample,
change it in the class definition as well.
And Make sure your class fields have the same types as in the JSON, and their getters and setters are correctly implemented.

Using Amazon's Java Alexa Skill Kit, can I put a custom Java object into a session attribute?

I'm using the Alexa Skill Kit for Java to build a custom Skill. I am trying to use a custom session attribute, co.prosody.util.PaInputData, in com.amazon.speech.speechlet.Session.
No trouble with session.setAttribute("inputData", paInputData), but when I retrieve the attribute (PaInputData)session.getAttribute("inputData"), I get a class cast exception:
"errorMessage": "java.util.LinkedHashMap cannot be cast to co.prosody.util.PaInputData"
Is it possible to get my object back?
Attribute objects that belong to the session that are not Strings will be turned into Linked Hash Maps, mapping the name of each instance variable to that of its value. For Objects that are not too complex, you can simply fetch these values by accessing each key of the Linked Hash Map that is associated with this object that belongs to your session's attributes, and reconstruct the object that way. (Note that you will need getters associated with your instance variables) You will not, however, be able to directly cast whatever object was stored in the attributes of your session to the object you desire/expect.
So let's say, for example, I have an Dog object, with two fields:
public class Dog{
private String name = "Spot";
private int age = 20;
public Dog(){
}
public Dog(String nIn, int aIn){
name = nIn;
age = aIn;
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
}
If this was stored in my session's attributes with a key of "MY_DOG", I could reconstruct the object this way:
LinkedHashMap<String, Object> myDog = (LinkedHashMap<String, Object>)session.getAttribute("MY_DOG");
String fetchedName = (String)myDog.get("name"); //this will return "Spot"
int fetchedAge = (Integer)myDog.get("age"); //this will return 20
Dog copyDog = new Dog(fetchedName, age);//effectively copies the Dog object

Getting the following error no single-String constructor/factory method

Below is the json string that i am parsing using jackson in java
String rspString = "{\"currency\": [{\"USD\": [\"U.S.Dollar\",\"$\"]},\"USD\"]}";
JsonUtil jsonUtil = new JsonUtil();
API1Response configAPI1Rsp = new API1Response();
API1Rsp = (API1Response) jsonUtil.Json2Object(rspString, configAPI1Rsp);
public class API1Response
{
#JsonProperty("Currency")
public List<Currency> currency;
//getters and setters
}
public class Currency()
{
#JsonProperty("USD")
public List<USD> USD
//getters and Setters
}
when i run the above code i am getting the below error:
Can not instantiate value of type [simple type, class com.sample.test.Currency] from String value ('USD'); no single-String constructor/factory method
in the above response string how to treat USD ( last one in the object) how to define in java for that object.
Thanks in Advance.
#JsonProperty("Currency") - Make sure "Currency" should be in lower case as it is in json string.
Your currency key in Json is array of Object and a String whilst you are converting array of Objects to Java object. So you need to modify the json string such that it only contains the objects. I.e. second element "USD" is not the object hence you are getting the error "no single-String constructor/factory method".
How about,
public class wallet {
List<Currency> currency;
}
and
"{\"currency\": [{\"USD\": [\"U.S.Dollar\",\"$\"]},]}"; or
"{\"currency\": [{\"USD\": [\"U.S.Dollar\",\"$\"]},\"USD\":[]]}";

How to get original class of a field declared in java class

Here we go, suppose if i have class Name :
class Name {
String firstName, lastName;
// getters and setters, etc.
}
and then Name class's object is declared somewhere in other class :
class Other {
Name name;
// getter and setters, etc.
}
Now if i do something like :
Other o = new Other();
Field[] fields = o.getClass().getDeclaredFields();
fields[0] --> is 'name' the Object of 'Name' class
but when i say field[0].getClass() :
It gives me java.lang.reflect.Field class object and not Name class object.
How can i get original class object from a field like 'name'
Field.getType method returns a Class object that identifies the declared type for the field represented by this Field object.
This should help
Other o = new Other();
Class<?> classTemp1 = o.getClass();
Field[] allFields = classTemp1.getDeclaredFields();
Now u can query each field for name ,type etc
fields[i].getType()
Please check
http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Field.html#getType()
getType() Returns a Type object that represents the declared type for the field represented by this Field object.
field[0].getClass()
Will return you the Type object that represents field[0] which is obiviously field[0].
Basically, you need to ask the field for the value of a specific instance, something like
Name name = (Name)fields[0].get(o);
Now. It's pretty dangrous to do a blind cast like this, I'd be probably simply assign it to a Object first and then do instanceof or maybe use Field#getName to determine the name of the field and take action from there...
nb- I'd make mention of getType, but Evgeniy Dorofeev beat me to it and I don't want take away from his answer
Based on Evgeniy's answer, this line is what you are looking for:
String actualClassName = fields[0].getType().getName();

Categories

Resources