Dynamic objects in java

Java classes with dynamic fields

AFAIK, this is not possible. You can only get type-safety without type casts if you use static typing. Static typing means method signatures (in classes or interfaces) that are known at compile time.

The best you can do is have an interface with a bunch of methods like String getStringValue(String field) , int getIntValue(String field) and so on. And of course you can only do that for a predetermined set of types. Any field whose type is not in that set will require a typecast.

If you look at my type-safe object map, you’ll see it’s in fact possible to be dynamic and type safe — without casts and without one method per type. When that idea struck me, I was curious if there was an even better solution. Hence my question.

Yes, but each of the attributes with a TypedMapKey type must be statically declared to achieve static typing. And as I said, there is a hidden typecast in the generated code anyway. Hence, I don’t see how what you proposed is dynamic fields without typecasts.

To clarify: The user of the map doesn’t have to cast all the time plus code-completion will insert the correct type.

Sorry, you won’t convince me that this gives you typesafe dynamic fields w/o typecasts. The names of the fields have to be static, and the values are only typesafe because of the hidden typecasts. Its a sham.

The obvious answer is to use a HashMap (or a LinkedHashMap if you care for the order of fields). Then, you can add dynamic fields via a get(String name) and a set(String name, Object value) method.

This code can be implemented in a common base class. Since there are only a few methods, it’s also simple to use delegation if you need to extend something else.

To avoid the casting issue, you can use a type-safe object map:

 TypedMap map = new TypedMap(); String expected = "Hallo"; map.set( KEY1, expected ); String value = map.get( KEY1 ); // Look Ma, no cast! assertEquals( expected, value ); List list = new ArrayList (); map.set( KEY2, list ); List valueList = map.get( KEY2 ); // Even with generics assertEquals( list, valueList ); 

The trick here is the key which contains the type information:

TypedMapKey KEY1 = new TypedMapKey( "key1" ); TypedMapKey KEY2 = new TypedMapKey( "key2" ); 

The performance will be OK.

Field reuse is by using the same value type or by extending the key class of the type-safe object map with additional functionality.

Calculated fields could be implemented with a second map that stores Future instances which do the calculation.

Since all the manipulation happens in just two (or at least a few) methods, sending signals is simple and can be done any way you like.

To implement automatic parent/child handling, install a signal listener on the «set parent» signal of the child and then add the child to the new parent (and remove it from the old one if necessary).

Since no framework is used and no tricks are necessary, the resulting code should be pretty clean and easy to understand. Not using String as keys has the additional benefit that people won’t litter the code with string literals.

Источник

Dynamically create an object in java from a class name and set class fields by using a List with data

I have a List that contains data with String type -> [«classField1», «classField2», «classField3»] I have a method ( myMethod(List list, String className) ) that accept as parameter the List. So, I can pass this List through the parameter to myMethod(List list, String className). In myMethod , I want to create one object, that will be instance of the className, that is the second parameter. After that I want to set the fields of the class by using the data of the List. Due to the fact that I want to obtain dynamically the fields of the class, the result of the above is that I have to cast each String value of the list, to the type of each field of the class. I am sure that the order of the Strings inside to the List, are in the right order, and correspond to the fields of the class with the same order. Does anybody have any idea how to perform the above? Example: [«StringtempValue», «StringUnitOfMeasurement»] => Create instance object:

I try to give a solution with the following way: Actually I want to create an object of an existing class and I tried to do that with reflection. I use the following code:

Class cls = Class.forName(name); Object clsInstance = (Object) cls.newInstance(); Field[] objectFields = clsInstance.getClass().getDeclaredFields(); 

But I get an exception to the 2nd line, when it tries to create the new object. As @JB Nijet said I didn’t know that the method getDeclaredFields() does not return the fields sorted. Actually, I have a method that accept only List of Strings, so by using reflection I convert the object to List of string, and after that I want to do the opposite. I didn’t think any other way to do it.

Both getFields() and getDeclaredFields() documentation says: «The elements in the array returned are not sorted and are not in any particular order». So I wonder on which kind of order of the fields you rely.

I’m not sure if you want to create and fill a object of a existing class (in that case, like @PeterLawrey suggested, you need reflection), or if you want to dynamically create and compile a new class and return an empty instance of that class. For the second requirement you need to study the javax.tools.JavaCompiler API or a Bytecode manipulation library such as ASM or BCEL.

3 Answers 3

Dynamic instantiation of objects can get pretty complex, and your scenario touches upon several aspects:

  • converting the object values from String to the appropriate type
  • loading the right class from the class name and creating an instance
  • assigning those values into the object

A thorough discussion of each of those points would take up an entire chapter in a no-doubt riveting treatment of Java as a dynamic language. But, assuming you don’t have the time to learn these intricacies, or take a dependency on some huge third party library, let’s whip up something that gets you on your way. Please keep your hands inside the vehicle at all times as the ride is going to get bumpy.

Let’s tackle the issue of type conversion first. The values are provided as Strings , but your object will store them as double , long , int , etc. So we need a function that parses a String into the appropriate target type:

static Object convert(Class target, String s) < if (target == Object.class || target == String.class || s == null) < return s; >if (target == Character.class || target == char.class) < return s.charAt(0); >if (target == Byte.class || target == byte.class) < return Byte.parseByte(s); >if (target == Short.class || target == short.class) < return Short.parseShort(s); >if (target == Integer.class || target == int.class) < return Integer.parseInt(s); >if (target == Long.class || target == long.class) < return Long.parseLong(s); >if (target == Float.class || target == float.class) < return Float.parseFloat(s); >if (target == Double.class || target == double.class) < return Double.parseDouble(s); >if (target == Boolean.class || target == boolean.class) < return Boolean.parseBoolean(s); >throw new IllegalArgumentException("Don't know how to convert to " + target); > 

Ugh. This is ugly and handles only intrinsic types. But we’re not looking for perfection here, right? So please enhance as appropriate. Note the conversion from String to some other type is effectively a form of deserialization, and so you’re placing constraints on your clients (whoever is giving you the Strings ) to provide their values in specific formats. In this case, the formats are defined by the behavior of the parse methods. Exercise 1: At some point in the future, change the format in a backwards incompatible way to incur someone’s wrath.

Now let’s do the actual instantiation:

static Object instantiate(List args, String className) throws Exception < // Load the class. Classclazz = Class.forName(className); // Search for an "appropriate" constructor. for (Constructor ctor : clazz.getConstructors()) < Class[] paramTypes = ctor.getParameterTypes(); // If the arity matches, let's use it. if (args.size() == paramTypes.length) < // Convert the String arguments into the parameters' types. Object[] convertedArgs = new Object[args.size()]; for (int i = 0; i < convertedArgs.length; i++) < convertedArgs[i] = convert(paramTypes[i], args.get(i)); >// Instantiate the object with the converted arguments. return ctor.newInstance(convertedArgs); > > throw new IllegalArgumentException("Don't know how to instantiate " + className); > 

We’re taking a lot of shortcuts here, but hey this isn’t the sistine chapel we’re creating. Simply load the class and search for a constructor whose number of parameters matches the number of arguments (i.e., arity). Overloaded constructors of the same arity? Nope, not gonna work. Varargs? Nope, not gonna work. Non-public constructors? Nope, not gonna work. And if you can’t guarantee your class will provide a constructor that sets all the fields like your example TempStruct does, then I’ll call it a day and grab a beer, because this approach is DOA.

Once we find the constructor, loop over the String args to convert them to the types expected by the constructor. Assuming that works, we then invoke the constructor via reflection, wave the magic wand and say abracadabra. Voilà: you have a new object.

Let’s try it with an extremely contrived example:

public static void main(String[] args) throws Exception

Источник

Create Objects Dynamically in Java

Is there a (better) way to dynamically create Objects? Right now I’m using a simple ‘factory pattern’ solution as following:

 String classType = generalObject.getClass().toString(); if(classType.equals("class be.testApp.UserObject")) < return UserObject.fromByteArray(data); //return new UserObject(); >else if(classType.equals("class.be.testApp.NewsObject")) < return NewsObject.fromByteArray(data); //return new NewsObject(); >

Please do not use toString to get your class as a String. use getPackage and getName instead — or use the class attribute.

Try using getClass().getName() instead of getClass().toString() . At least you’ll get rid of the unreadable «class » part of the string. Better: use Class type = generalObject.getClass(); and if (type.equals(UserObject.class)) .

3 Answers 3

This code is not a factory pattern and no object is created. You evaluate the class name and call a static method on a class.

Now it looks like you have an object ( generalObject ) and want to create a new instance of the very same type. If all possible types have a public default constructor (convention!), then you can use this to create a new instance based on the given object:

Object newObject = generalObject.getClass().newInstance(); 

(but maybe I still didn’t get your idea. )

I’ll try to briefly explain it. I’ve created a general DataObject class which is used by a few different Databases so I can generelise the use of it (e.g. addData(DataObject data)) in the database superclass. But I have several more explicit Classes (UserObject) that inherit basic db stuff from DataObject, but add specifik properties. I could use the method you suggest, only there are no objects stored in the database, but bytes are (that’s why I use the fromByteArray method).

Источник

Dynamically create and cast objects at runtime

Class B is also on the same lines except that its member variable is named member2 and gets intitialized to say 20 inside the constructor. My Requirement : At runtime , I get a string which contains a className ( could be A or B). I want to dynamically create an object of this class along with invoking the constructor. How can I achieve this . I don’t want to use interfaces for common functionality of above classes Morever, later on I set the properties of this raw object using Propery Builder Bean Util class based on a list of columns .

Class clazz = Class.forName("className"); Obj obj = clazz.newInstance(); 

Hi there, I slightly edited your question to format your Java code better. As far as I can tell on StackOverflow code looks nicer if you select it and click on the «10010001» icon, shifting all your code to the right (it then gets formated) rather then using the xml tag.

You can’t do that, but you could have a third class, say Common (either a class or Java interface) and then have A extends Common and B extends Common or A implements Common and B implement Common and put the common functionalities in the «Common» class/interface. From your question it looks like there’s shared common functionalities.

I don’t want an interface here as the Type T classes here are domain classed much different in their behaviour . Above was just an example functionality to give an idea of what I am trying to accomplish and doesn’t represent the correct state of my code. Now what ?

Источник

Читайте также:  Add two list java
Оцените статью