I want to "flatten"/transform an instance from a given Java class to another instance containing primitive types only.
Every field from an object that is not already a primitive type will have to be flattened recursively too, so that the resulting object contains a flattened view of the original one, with primitive types only.
For example, given the following classes:
class Element {
int id_;
Position position_;
}
class Position {
int x_;
int y_;
}
The resulting instance would be of type:
class FlattenedElement {
int id_;
int x_;
int y_;
}
And I would expect such a behaviour:
Element e = new Person ( 42, new Position(0, 0) );
FlattenedElement fe = e.flatten();
Is there any tool/library able to do so?
Or do I need to write my own flattener, using the reflection API I take it?
-- edit following most comments --
I changed my example to avoid any confusion with String and byte (I won't have to deal with Strings).
I need to keep the semantics of the data in the resulting conversion. The output primitive types data will be directly involved in a parallel computation using OpenCL, which only understands primitive data types.
In other words, what I need is to break encapsulation to manipulate directly the primitive data types embedded in the class hierarchy.
You can do this, but you will need a third party library to create the new class, like Javaassist. To introspect the class to be flattened, you will use reflection as some users already said. Here is another example that I wrote for you:
public static Class flatten( Class classToFlatten ) {
for ( Field f : classToFlatten.getDeclaredFields() ) {
Class type = f.getType();
String name = f.getName();
int modifiersConfig = f.getModifiers();
// extract all modifiers here (using the isXXX methods of the Modifier class)
System.out.print( Modifier.isPrivate( modifiersConfig ) ? "private" : "" );
System.out.print( " " + type );
System.out.print( " " + name );
System.out.println();
if ( type.isPrimitive() ) {
// primitive type.
// does not need to be converted.
// insert in the new class as it is (using Javaassist).
} else {
// no primitive type.
// needs to be converted and tested.
// insert in the new class after the conversion (using Javaassist).
// convert rules...
switch ( type.getSimpleName() ) {
case "String":
// insert in the new class a array of chars.
break;
// cases to test if the field is a wrapper (Integer, Long, etc.).
// other rules tha you need here...
}
// here you need to use recursion...
// you can use this method, but you will need to create
// a new parameter, passing the class that is been built
// to insert new fields in it (relative to the type that is been
// reflected)
}
}
// return the new class here and outside the method, use the newInstance
// method to create new instances of this class
return null;
}
With this I think you will be able to do what you need, but I thinking why you need this. You will have some problems when you have arrays of some type that will be recursively flettened, because you will maybe need to "backtrack" to resolve their type or to run the flatten algorithm some times. With generics, inner classes, methods and all kinds of class members you will have the same problem. I'm not sayng that this is impossible, but it will consume a lot of your time and maybe you could solve your problem in a simpler way as some users already said. Well, I hope you can do what you need and I want to know the results if possible! Maybe your solution can be the seed of a new library! Ok, enought of brainstorming :D Here are some links.
The Javaassist library can be downloaded here.
Here you can see a simple tutorial. I suggest that you use it only to begin, because the Javaassist API may have been improved since the creation of the tutorial, so, after reading this, refactor your code (if possible), reading the library docs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With