I'm being given a Json file with the form:
{
"descriptions": {
"desc1": "someString",
"desc2": {"name":"someName", "val": 7.0}
}
}
I have the POJO:
public class CustomClass {
Map<String, Object> descriptions;
public static class NameVal{
String name;
double val;
public NameVal(String name, double val){...}
}
}
I can recreate the json file with the code:
CustomClass a = new CustomClass();
a.descriptions = new HashMap<String, Object>();
a.descriptions.put("desc1", "someString");
a.descriptions.put("desc2", new CustomClass.NameVal("someName", 7.0));
new ObjectMapper().writeValue(new File("testfile"), a);
But, when I read the object back in using:
CustomClass fromFile = new ObjectMapper().readValue(new File("testfile"), CustomClass.class);
then fromFile.descriptions.get("desc2") is of type LinkedHashMap instead of type CustomClass.NameVal.
How can I get Jackson to properly parse the type of the CustomClass.NameVal descriptors (other than making some class that wraps the parsing and explicitly converts the LinkedHashMap after Jackson reads the file)?
Try this. Create a class Description with name and value attributes:
public class Description {
private String name;
private double val;
}
Now in your CustomClass do this:
public class CustomClass {
List<Description> descriptions;
}
And that's it. Remember to create getters and setters because Jackson needs it.
You could try something like this:
public class DescriptionWrapper {
private Description descriptions;
public Description getDescriptions() {
return descriptions;
}
public void setDescriptions(Description descriptions) {
this.descriptions = descriptions;
}
}
public class Description {
private String desc1;
private NameValue desc2;
public String getDesc1() {
return desc1;
}
public void setDesc1(String desc1) {
this.desc1 = desc1;
}
public NameValue getDesc2() {
return desc2;
}
public void setDesc2(NameValue desc2) {
this.desc2 = desc2;
}
}
public class NameValue {
private String name;
private double val;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getVal() {
return val;
}
public void setVal(double val) {
this.val = val;
}
}
Related
I understand there may be cleaner ways to store these data, I'm skipping that part for the sake of my sanity in dealing with legacy code.
I want to store an object that looks like this in DynamoDB:
#DynamoDBTable(tableName="TableName")
public class MyItem {
// DynamoDB Attributes
private String hashKey;
private String someAttribute;
private Map<String, Config> configs;
#DynamoDBHashKey(attributeName = "hash_key")
public String getHashKey() {
return this.hashKey;
}
public void setHashKey(String hashKey) {
this.hashKey = hashKey;
}
#DynamoDBAttribute(attributeName = "some_attribute")
public String getSomeAttribute() {
return this.someAttribute;
}
public void setSomeAttribute(String someAttribute ) {
this.someAttribute = someAttribute;
}
#DynamoDBAttribute(attributeName = "configs")
public Map<String, Config> getConfigs() {
return this.configs;
}
public void setConfigs(Map<String, Config> configs)
{
this.configs = configs;
}
}
With a supplemental class
#DynamoDBDocument
public class Config {
private String field;
#DynamoDBAttribute(attributeName="field")
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
Will this work as written?
What would the resulting entry look like in DynamoDB for the following JSON:
{
"hash_key":"123",
"some_attribute":"attribute_value",
"a_config_key" : {
"field":"field_value"
}
}
I would recommend you to implement your own converter using #DynamoDbConvertedBy (the official dynamodb-enhanced client).
Hopefully, this sample is helpful: https://stackoverflow.com/a/70602166/12869305
I am trying to assign the value returned by some function to a field in the deserialized class of json.
FileInfo.java
public class FileInfo {
#SerializedName("Name")
private String mName;
#SerializedName("Url")
private String mUri;
#SerializedName("Size")
private Integer mSize;
#SerializedName("ModTime")
private Long mModifiedTime;
private FileType mType;
#SerializedName("Children")
private ArrayList<FileInfo> mChildren = new ArrayList<>();
public ArrayList<FileInfo> getChildren() {
return mChildren;
}
public long getModifiedTime() {
return mModifiedTime;
}
public String getName() {
return mName;
}
public Integer getSize() {
return mSize;
}
public String getUrl() {
return mUri;
}
public FileType getType() {
return mType;
}
public void setChildren(ArrayList<FileInfo> mChildren) {
this.mChildren = mChildren;
}
public void setModifiedTime(long mModifiedTime) {
this.mModifiedTime = mModifiedTime;
}
public void setName(String mName) {
this.mName = mName;
}
public void setSize(Integer mSize) {
this.mSize = mSize;
}
public void setType(FileType mType) {
this.mType = mType;
}
public void setUri(String mUri) {
this.mUri = mUri;
}
#Override
public String toString() {
return FileInfo.class.toString();
}
public FileInfo() {
}
}
The mType needs to be assigned to foo(mName). I looked up custom deserializers and instance creators but none of those helped. I also thought of TypeAdapters which i feel defeats the purpose of keeping deserialization(using GSON) simple.
This is a sample JSON string that will be deserialized.
[
{
"Name":"Airport",
"Url":"http://192.168.2.2/api/sites/Baltimore%20Airport/Airport",
"Size":0,
"ModTime":"2015-12-02T14:19:17.29824-05:00",
"Children":null
}
]
P.S. I'm not sure if this should be done during deserialization but trying anyways. Also please let me know of alternative ways to achieve this.
I'm facing this task:
I have class A and class B. These two classes are different but almost the same.
I need to somehow merge them into 1 Single array of objects so I will be able to use them later in a list that combines both classes.
Class A:
public class Followers {
private String request_id;
private String number_sender;
private String state;
public String getRequest_id() {
return request_id;
}
public String getNumber_sender() {
return number_sender;
}
public String getState() {
return state;
}
}
Class B:
public class Following {
private String name;
private String state;
private String request_id;
public String getRequest_id() {
return request_id;
}
public String getName() {
return name;
}
public String getState() {
return state;
}
}
I've tried doing this next move:
Object[] obj1 = (Object[]) followers;
Object[] obj2 = (Object[]) followings;
Object[] completeArray = ArrayUtils.addAll(obj1, obj2);
Where followers and followings are both arrays of the corresponding classes. Then in my list adapter I use:
if (values[currentItem] instanceof Followers) { BLA BLA BLA}
else if (values[currentItem] instanceof Following) { BLA BLA BLA}
But I get this exception:
Caused by: java.lang.ArrayStoreException: source[0] of type json.objects.Following cannot be stored in destination array of type json.objects.Followers[]
What will be the best way to merge two arrays of different objects into one array?
Will just implementing the same interface between them do the job and then they will basically be in an array of the interface type?
what other ways do you recommend?
Try this
Object[] completeArray = new Object[0];
completeArray = ArrayUtils.addAll(completeArray, obj1);
completeArray = ArrayUtils.addAll(completeArray, obj2);
If you make both classes implement a common interface you can manipulate arrays/lists of them as if they contains instances of the interface.
public interface Follow {
public String getRequest_id();
public String getState();
}
public class Follower implements Follow {
private String request_id;
private String number_sender;
private String state;
public String getRequest_id() {
return request_id;
}
public String getNumber_sender() {
return number_sender;
}
public String getState() {
return state;
}
}
public class Following implements Follow {
private String name;
private String state;
private String request_id;
public String getRequest_id() {
return request_id;
}
public String getName() {
return name;
}
public String getState() {
return state;
}
}
public void test() {
List<Follow> all = new ArrayList<>();
all.add(new Following());
all.add(new Follower());
for ( Follow f : all ) {
String id = f.getRequest_id();
String state = f.getState();
}
}
Alternatively you could put them in a hierarchy:
public class Entity {
private String request_id;
private String state;
public String getRequest_id() {
return request_id;
}
public String getState() {
return state;
}
}
public class Follower extends Entity {
private String number_sender;
public String getNumber_sender() {
return number_sender;
}
}
public class Following extends Entity {
private String name;
public String getName() {
return name;
}
}
public void test() {
List<Entity> all = new ArrayList<>();
all.add(new Following());
all.add(new Follower());
for ( Entity f : all ) {
String id = f.getRequest_id();
String state = f.getState();
}
}
Or you could make the extra fields into attributes.
enum Attribute {
Follows,
Followed;
}
public static class Entity {
private String request_id;
private String state;
EnumMap<Attribute, String> attributes = new EnumMap<>(Attribute.class);
public String getRequest_id() {
return request_id;
}
public String getState() {
return state;
}
// Factory to make entities.
static Entity make(Attribute attribute, String value) {
Entity e = new Entity();
e.attributes.put(attribute, value);
return e;
}
}
public void test() {
List<Entity> all = new ArrayList<>();
all.add(Entity.make(Attribute.Follows, "Fred"));
all.add(Entity.make(Attribute.Followed, "Gill"));
for (Entity f : all) {
String id = f.getRequest_id();
String state = f.getState();
}
}
There are an infinite number of possibilities.
USE concat
var combined= obj1.concat(obj2); // Merges both arrays
Try this.
private Object[] appendObj(Object[] obj, Object newObj) {
ArrayList<Object> temp = new ArrayList<Object>(Arrays.asList(obj));
temp.add(newObj);
return temp.toArray();
}
I'm new to GSON and have been having trouble parsing the JSON below. The parsing works fine until it gets to the list of bills (staring at "0":). At that point I get a null reference in the resulting gson.fromJson object. If those bills were specified in a JSON array I think it would be easy, but they're not and I can't change that. What is the best way to handle this situation?
{
"status":"OK",
"masterlist":{
"session":{
"session_id":1007,
"session_name":"97th Legislature"
},
"0":{
"bill_id":446875,
"number":"HB4001"
},
"1":{
"bill_id":446858,
"number":"HB4002"
},
"2":{
"bill_id":446842,
"number":"HB4003"
},...
This is the code in my main method:
InputStream source = retrieveStream(url);
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
ResponseData response = gson.fromJson(reader, ResponseData.class);
And this is the ResponseData class:
public class ResponseData {
private String status;
private MasterList masterlist;
public static class MasterList{
private Session session;
private Bill bill; //Also tried: Map<String, String> bill;
}
public static class Session{
private String session_id;
private String session_name;
}
public static class Bill{
private String bill_id;
private String number;
}
}
You can map the object as below:
declare an object to map with json string
public class ResponseData {
private String status;
private Map<String, MasterList> masterlist;
public Map<String, MasterList> getMasterlist() {
return masterlist;
}
public void setMasterlist(Map<String, MasterList> masterlist) {
this.masterlist = masterlist;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public static class MasterList {
private String session_id;
private String session_name;
private String bill_id;
private String number;
public String getSession_id() {
return session_id;
}
public void setSession_id(String session_id) {
this.session_id = session_id;
}
public String getSession_name() {
return session_name;
}
public void setSession_name(String session_name) {
this.session_name = session_name;
}
public String getBill_id() {
return bill_id;
}
public void setBill_id(String bill_id) {
this.bill_id = bill_id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
}
And use it as below:
String data = "{\"status\":\"OK\",\"masterlist\":{ \"session\":{ \"session_id\":1007, \"session_name\":\"97th Legislature\" }, \"0\":{ \"bill_id\":446875, \"number\":\"HB4001\" }, \"1\":{ \"bill_id\":446858, \"number\":\"HB4002\" }, \"2\":{ \"bill_id\":446842, \"number\":\"HB4003\" }}}";
Gson gson = new Gson();
ResponseData response = gson.fromJson(data, ResponseData.class);
for (Iterator<Entry<String, MasterList>> it = response.getMasterlist().entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, MasterList> entry = it.next();
System.out.println(entry.getKey());
System.out.println(entry.getValue().getSession_id());
}
I am using jackson 2.2 annotation #JsonProperty with required set to true. While deserializing json file which doesn't contain that property via ObjectMapper readValue() method no exception is being thrown.
Is it supposed to work in a different way or did I missed something?
My dto class:
public class User {
public enum Gender {MALE, FEMALE}
;
public static class Name {
private String _first, _last;
public String getFirst() {
return _first;
}
public String getLast() {
return _last;
}
public void setFirst(String s) {
_first = s;
}
public void setLast(String s) {
_last = s;
}
}
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
#JsonProperty(value ="NAAME",required = true)
public Name getName() {
return _name;
}
#JsonProperty("VERIFIED")
public boolean isVerified() {
return _isVerified;
}
#JsonProperty("GENDER")
public Gender getGender() {
return _gender;
}
#JsonProperty("IMG")
public byte[] getUserImage() {
return _userImage;
}
#JsonProperty(value ="NAAME",required = true)
public void setName(Name n) {
_name = n;
}
#JsonProperty("VERIFIED")
public void setVerified(boolean b) {
_isVerified = b;
}
#JsonProperty("GENDER")
public void setGender(Gender g) {
_gender = g;
}
#JsonProperty("IMG")
public void setUserImage(byte[] b) {
_userImage = b;
}
}
This is how do I deserialize the class:
public class Serializer {
private ObjectMapper mapper;
public Serializer() {
mapper = new ObjectMapper();
SimpleModule sm = new SimpleModule("PIF deserialization");
mapper.registerModule(sm);
}
public void writeUser(File filename, User user) throws IOException {
mapper.writeValue(filename, user);
}
public User readUser(File filename) throws IOException {
return mapper.readValue(filename, User.class);
}
}
This is how it is actually called:
Serializer serializer = new Serializer();
User result = serializer.readUser(new File("user.json"));
Actuall json looks like:
{"GENDER":"FEMALE","VERIFIED":true,"IMG":"AQ8="}
I would expect that since _name is not specified in json file and is required that the exception will be thrown.
With Jackson 2.6 you can use required, however you have to do it using JsonCreator
For example:
public class MyClass {
#JsonCreator
public MyClass(#JsonProperty(value = "x", required = true) Integer x, #JsonProperty(value = "value_y", required = true) Integer y) {
this.x = x;
this.y = y;
}
private Integer x;
private Integer y;
}
If x or y are not present an exception will be thrown when trying to deserialize it.
As per Jackson annotations javadocs: "Note that as of 2.0, this property is NOT used by BeanDeserializer: support is expected to be added for a later minor version."
That is: no validation is performed using this settings. It is only (currently) used for generating JSON Schema, or by custom code.