How to set java object attribute like the way in javascript - java

All:
I have a data model object in Java like:
class Model {
String name;
String email;
}
What I want to do is dynamically determine what attribute I want to set by using a variable like in Javascript object;
String field = "name";
// This is what I try to achieve, not the real code.
New Model().field = "according content";
or
New Model()[field] = "according content";
Thanks

You could reflection as in this link
In this example they have
public long chapters = 0;
and can get/set it as
Field chap = c.getDeclaredField("chapters");
out.format(fmt, "before", "chapters", book.chapters);
chap.setLong(book, 12);
out.format(fmt, "after", "chapters", chap.getLong(book));

Related

How to access and read the values of child objects of an object?

Here is how I am constructing an Object inside a method:
//right after creating the class
public static ArrayList<Object> old_devicelist = new ArrayList<Object>();
//inside a method
Date date = new Date();
long time = date.getTime();
Integer opened = 0;
String deviceId = "";
String dev_rssi = "";
Object[] MyObject = new Object[]{time, opened, deviceId, dev_rssi};
old_devicelist.add(MyObject);
Now, I would like to loop through that ArrayList and access some elements (note that deviceId might at some point contain an object and I would like to access id field of it) inside it, then I would like to use them like this, for ex. :
if(device.id == 33){
//do something...
}
You're using an array with type Object and then you're storing these object arrays into a list. This makes it hard to retrieve the information later.
Consider this instead:
public static List<Device> DEVICES = new ArrayList<>();
class Device {
Date date;
long time;
Integer opened;
String deviceId;
String deviceRssi
Device(Date date, Integer opened, String deviceId, String deviceRssi) {
this.date = date;
this.time = date.getTime();
this.opened = opened;
this.deviceId = deviceId;
this.deviceRssi = deviceRssi;
}
}
Device first = new Device(
new Date(),
0,
"",
"");
DEVICES.add(first);
System.out.println(DEVICES.get(0).deviceId);
...
for (Device device : DEVICES) {
if (device.deviceId.equals("33)) {
// ...
}
}
I'd recommend not using too many static/global variables and reading about the Java Naming Convention.
I guess you should create new class instead of using Object.
public class DeviceSpecification { //or any other name
long time;
Integer opened;
String deviceId;
String dev_rssi;
public DeviceSpecification(long time, Integer opened, String deviceId, String dev_rssi) {
this.time = time;
this.opened = opened;
this.deviceId = deviceId;
this.dev_rssi = dev_rssi;
}
}
Create a list with specific type:
public static List<DeviceSpecification> oldDeviceCollection = new ArrayList<>();
Create an instance of a class
DeviceSpecification device = new DeviceSpecification(new Date().getTime(), 0, "", "")
Add the instance to a list
oldDeviceCollection.add(device);
Use it in query - we can use streams from Java 8
oldDeviceCollection.stream()
.forEach(
device -> {
if(device.id.equals("33")) {
// do something
}
);
First of all your Arraylist takes Objects and you are trying to add an Object array so if your goal is to keep object arrays with the device_id you should change your Arraylist to
public static ArrayList<Object[]> old_devicelist = new ArrayList();
Taking that in mind you can access any deviceid by typing
old_devicelist.get(i)[2]
where i is the element you want and 2 because you have setted device_id to be the 3rd element of your Object array!
Hope this helps!

What is the equivalent of a C# object variable in Java?

I have this C# code:
var invoice = new {
code = "01",
otherThings = "etc",
...
}
What would be the equivalent of this in Java?
I tried creating a: Object[] invoice = new Object[]{} but don't know how to fill the object.
I hope I was clear enough, thanks.
You can write it like that:
Invoice i = new Invoice(){...};
But thats not Clean Code.
just write a constructor with all properties like:
public invoice(String code, String otherThings)
{
this.code = code;
this.otherThings = otherThings;
}
...
Invoice i = new Invoice("asdfasdf", "asdfasdf");
Oject[] invoice = new Object[5];
invoice[0] = (Object)i;

Converting Jackson JSON object references to JSON.Net object references

I need to be able to deserialize a JSON string produced by Jackson (Java/Spring server) with a C#/JSON.Net client while keeping the object references intact. Jackson uses "#id":1...n for cyclic references, while the reference is denoted by a single integer. JSON.Net uses "$id" and "$ref".
Does anybody know how to convert a JSON string from Jackson to a JSON.Net compatible version?
Here is my solution:
Use these settings for JSON.Net:
JsonSerializerSettings settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
Use this interceptor to convert the references:
public static class JSONInterceptor
{
public static string sanitizeJSON(string originalJSONFromJava)
{
// Get ID right from Jackson to JSON.Net
string pattern = Regex.Escape(#"""#id"":") + "(\\d+)";
string replacement = #"""$id"":""$1""";
Regex rgx = new Regex(pattern);
string output = rgx.Replace(originalJSONFromJava, replacement);
// Convert Jackson reference in array
pattern = #",(\d+)";
replacement = #",{""$ref"":""$1""}";
rgx = new Regex(pattern);
output = rgx.Replace(output, replacement);
// Convert single Jackson reference to ref
pattern = Regex.Escape(#"""\\w+"":") + "(\\d+)";
replacement = #"""$ref"":""$1""";
rgx = new Regex(pattern);
output = rgx.Replace(output, replacement);
return output;
}
}
Call the interceptor and deserialize like this:
asset = JsonConvert.DeserializeObject<Asset>(JSONInterceptor.sanitizeJSON(response), settings);
The asset class has this layout:
public class Asset {
....
// Parent asset
public Asset parent;
// Asset agents
public List<Agents> agent;
....
}
So, Jackson produces something like:
{"#id":1,......."parent":{"#id":15,.....},"agents":[{"#id":6, ......},12,{...}]...}
which needs to be converted into something like (JSON.Net):
{"$id":"1",...,"$ref":"15",....,"agents":[{...,"$ref":"6",...]}
This is what the code above does.
Hope this helps somebody.

how to add user defined type attribute in proto(Google Protocol Buffer) programatically

I want to create .proto file through java code. I am able to do it with message having primitive type attributes as follow :
public void testDynamicProto() throws Exception {
byte[] bytes = buildPersonProtoDesc();
byte[] personBytes = buildPersonProto(bytes);
Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor
.buildFrom(
DescriptorProtos.FileDescriptorProto.parseFrom(bytes),
new Descriptors.FileDescriptor[0]);
Descriptors.Descriptor personDesc = fileDescriptor
.findMessageTypeByName(PERSON_MESSAGE);
DynamicMessage message = DynamicMessage.parseFrom(personDesc,
personBytes);
for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : message
.getAllFields().entrySet()) {
// TODO: add asserts
System.out.println(entry.getKey().getName() + "------------"
+ entry.getValue());
}
// TODO: test repeated field
// TODO: test non destructive updates (addition of column) to person proto and make sure old protos can be parsed
}
private byte[] buildPersonProto(byte[] bytes)
throws Descriptors.DescriptorValidationException,
InvalidProtocolBufferException {
Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor
.buildFrom(
DescriptorProtos.FileDescriptorProto.parseFrom(bytes),
new Descriptors.FileDescriptor[0]);
Descriptors.Descriptor personDesc = fileDescriptor
.findMessageTypeByName(PERSON_MESSAGE);
DynamicMessage.Builder personBuilder = DynamicMessage
.newBuilder(personDesc);
personBuilder.setField(personDesc.findFieldByName(FNAME_FIELD), "Jon");
personBuilder.setField(personDesc.findFieldByName(LNAME_FIELD), "Doe");
personBuilder.setField(personDesc.findFieldByName(STATUS_FIELD), 2);
return personBuilder.build().toByteArray();
}
private byte[] buildPersonProtoDesc() {
DescriptorProtos.FileDescriptorProto.Builder fileDescriptorProtoBuilder = DescriptorProtos.FileDescriptorProto
.newBuilder();
DescriptorProtos.DescriptorProto.Builder messageProtoBuilderA = DescriptorProtos.DescriptorProto
.newBuilder();
messageProtoBuilderA.setName(PERSON_MESSAGE);
messageProtoBuilderA
.addFieldBuilder()
.setName(FNAME_FIELD)
.setNumber(1)
.setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_STRING);
messageProtoBuilderA
.addFieldBuilder()
.setName(LNAME_FIELD)
.setNumber(2)
.setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_STRING);
messageProtoBuilderA.addFieldBuilder().setName(STATUS_FIELD)
.setNumber(3)
.setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_INT32);
fileDescriptorProtoBuilder.addMessageType(messageProtoBuilderA);
DescriptorProtos.FileDescriptorProto fileDescriptorProto = fileDescriptorProtoBuilder
.build();
return fileDescriptorProto.toByteArray();
}
Now my proto structure is
message Person{
optional string FName=1;
optional string LName=2;
optional string Status=3;}
And I can achieve this by using above methods.
I want to achieve:
message Person{
optional string FName=1;
optional string LName=2;
optional string Status=3;
message Address {
optional string country=1;
optional string state=2;
optional string city=3;}
repeated Address address=4;}
Queries:
How to add Address under Person(can try method addRepeatedField but couldn't create FileDescriptor)
How to add Address as repeated field(ArrayList) under Person
Please give me any hint if anybody has.
To add a type under Person call addNestedType() on messageProtoBuilderA (the DescriptorProto.Builder for Person). The input for addNestedType() is a DescriptorProto for Address, which is built in the same way as the one for Person.
When adding the address field to the Person type, call setLabel(Label.LABEL_REPEATED) on the corresponding FieldDescriptorProto.Builder.
DescriptorProto.Builder messageProtoBuilderA = ...;
messageProtoBuilderA.addNestedType(createAddressType());
FieldDescriptorProto.Builder addressField = FieldDescriptorProto.newBuilder();
addressField.setName("address")
.setLabel(Label.LABEL_REPEATED)
.setNumber(4)
.setType(Type.TYPE_MESSAGE)
.setTypeName("Address");
messageProtoBuilderA.addField(addressField);
...
private DescriptorProto.Builder createAddressType() {
DescriptorProto.Builder addressProtoBuilder = DescriptorProto.newBuilder();
addressProtoBuilder.setName("Address");
// add fields
return addressProtoBuilder;
}
I believe for protos all the fields have to be together. So it should be
optional string FName=1;
optional string LName=2;
optional string Status=3;
repeated Address address=4;
and you can put this under your definition of Address so that code is already generated.

json Deserializer in to target object

Can you recommend on a Json Deserializer that can deserialize into existing object (merge 2 objects)?
When the user submit a form I want to save that into the db this way:
this is the json from the client:
{"affiliateId":1,"name":"First Affiliate","email":"email#gmail.com","user.userName":"test","user.password":"pass-hashed","employee.employeeId":1}
Affiliate affiliateFromDb = affiliateApi.getFromDbById(1);
SomeDeserialization json = new SomeDeserialization();
affiliateFromDb = json.fromJson(affiliateFromJson , affiliateFromDb );//affiliateFromDb = target bean
Meaning that I want the affiliateFromJson to be interpolated into affiliateFromDb.
And than I will call
affiliateApi.save(affiliateFromDb);
Note that the json contains deep deserialize, user.userName
Thanks
Use Gson! In particular, see the Object Examples.
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
The only catch here — but you will have this same problem with any other JSON (de)serializer — is the nonstandard "deep" object format you want to work with. You would have to use something like this instead:
{"affiliateId":1,"name":"First Affiliate","email":"email#gmail.com","user": {"userName":"test","password":"pass-hashed"},"employee.employeeId":1}
http://www.json.org/javadoc/org/json/JSONObject.html
JSONObject jsonResponse = new JSONObject(responseString);

Categories