patternjavaMinor
Using Reflection to Initialize Instance Variables
Viewed 0 times
reflectioninstanceusingvariablesinitialize
Problem
I'm facing the issue of how to reconstruct data across a network in Java. As part of my Component based game engine (read about it here, I have to encode components as XML on the server, send it to the client, and then reconstruct the appropriate component with all the data included in the XML. For example:
Right now, I use reflection on the client to construct a new TextureComponent (but this will work for any component with primitive data types) using the complete name of the class. I then sequentially read all the String parameters from the XML into the component using reflection in this BasicDecoder:
```
public class BasicDecoder implements DataDecoder {
@Override
public void decode(DataComponent component, String[] data) {
Class compClass = component.getClass();
// fills in all public fields with data in order
Field[] fields = compClass.getFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Class fieldType = field.getType();
String typeName = fieldType.getName().toUpperCase().replace(".", "");
FieldType type;
try {
type = FieldType.valueOf(typeName);
} catch (Exception ex) {
throw new RuntimeException("BasicDecoder cannot handle field: " + typeName);
}
try {
switch (type) {
case INT:
field.setInt(component, Integer.parseInt(data[i]));
break;
case DOUBLE:
field.setDouble(component, Double.parseDouble(data[i]));
break;
case BYTE:
field.setByte(component, Byte.parseByte(data[i]));
break;
case SHORT:
field.setShort(component, Short.parseShort(data[i]
package.TextureComponent
id 1 /id
width 100 /width
height 100 /height
/package.TextureComponentRight now, I use reflection on the client to construct a new TextureComponent (but this will work for any component with primitive data types) using the complete name of the class. I then sequentially read all the String parameters from the XML into the component using reflection in this BasicDecoder:
```
public class BasicDecoder implements DataDecoder {
@Override
public void decode(DataComponent component, String[] data) {
Class compClass = component.getClass();
// fills in all public fields with data in order
Field[] fields = compClass.getFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Class fieldType = field.getType();
String typeName = fieldType.getName().toUpperCase().replace(".", "");
FieldType type;
try {
type = FieldType.valueOf(typeName);
} catch (Exception ex) {
throw new RuntimeException("BasicDecoder cannot handle field: " + typeName);
}
try {
switch (type) {
case INT:
field.setInt(component, Integer.parseInt(data[i]));
break;
case DOUBLE:
field.setDouble(component, Double.parseDouble(data[i]));
break;
case BYTE:
field.setByte(component, Byte.parseByte(data[i]));
break;
case SHORT:
field.setShort(component, Short.parseShort(data[i]
Solution
Reflection is not the correct way to do this. You will need Serialization for this. Another option is to use XML marshalling and unmarshalling, but I am not so familiar with that.
For serialization I suggest you to pick up a copy of Effective Java, and read the last couple of items of the book, which are all about Serialization.
You really need to take care of the following, since you are dealing with a game and network:
I would recommend all your classes to implement a static inner classes called
Some other ad-hoc review points of your current code:
In general I would never let Reflection do such a task, I would add with the following code, either a public constructor taking all arguments of the object (which you can get from the
For serialization I suggest you to pick up a copy of Effective Java, and read the last couple of items of the book, which are all about Serialization.
You really need to take care of the following, since you are dealing with a game and network:
- Check your class invariants, constructors may not violate them.
- Make sure that your seriliazation is all safe as attackers can exploit a lot of things to do some quite surprising things.
- Take care of the evolvability of your classes, serialization does pose some issues on that.
I would recommend all your classes to implement a static inner classes called
ProxyHelper and implement the Proxy Serialization Pattern on the classes.Some other ad-hoc review points of your current code:
- Do not catch
Exception, catch the subclass(es) that you actually see happening, currently it will also catchRuntimeExceptions.
- Do preferably not throw
RuntimeException, but add somewhat more detail,IllegalStateExceptionmay be a candidate here.
- Follow the coding conventions, you do it quite well in general, but in the
switch (type) { }everycase(and inherited code lines) need to be indented one more factor.
In general I would never let Reflection do such a task, I would add with the following code, either a public constructor taking all arguments of the object (which you can get from the
String[] data), or if there are too many arguments (more than five usually), you can also emply the Builder Pattern.Context
StackExchange Code Review Q#49518, answer score: 5
Revisions (0)
No revisions yet.