Hi!
I'm writing a unit test where arbitrary objects have to be created without knowing anything about the objects (with some exceptions). I use reflection to create objects and set their fields to random values etc... I'm almost there but I've come to an issue I can't find a solution to.

Say that an Object that is instansiated using reflection has a field, which is a Map<Object, Object>. I set this field to an empty map.

The object has the following method:

public SomeObject doSomething(String aString) {
    SomeObject someObject = (SomeObject) map.get(aString);
    if(someObject == null) throw new SomeException();
    return someObject;
}

The problem is that my program want to set the map field in the Object instance to some random map. But it cant be totally random since later code depend on what is in that map. What will happen is that the value that is returned from map.get() will try to be cast to some specific type and fail, since I can't know what kind of map to create.

Is there a way to solve this? To somehow detect what the value of map.get() is going to be cast to or something?

Thanks!

/S

Recommended Answers

All 9 Replies

Can you create the map as Map<String, SomeObject > ?

Maybe, possibly, but I think your'e suggesting that I should return an object in the get method dependending on the value of the input String? That won't be possible since I can't know what string will be used as in parameter in the method doSomething(String).

My though right now is to just handle the creation of maps in a more specific way, by knowing what Object the map belongs to and its variable name, which I can do. It wouldn't be general and will require changing/adding new test code if the program is changed. I can't come up with any other way.

Maybe I haven't understood the question?
You already posted a method that gets the SomeObject corresponding to a String that's passed as a parameter.

Yes. But I won't be calling that method. The method will be called with a string that also is set via reflection. The point is to just create objects with arbitrary instance variables.

The test is going to be used to test transformation of objects that I have in my program. The test works like this:

1. A method "testTransformation" is called with "Class<?>" as input. Only classes inheriting from the interface "Transformable" will be used as input.

2. Try to create an object with type Class<?>. I do this with with reflection. instansiate the object and recursively populate its instance variables with dummy values. There are some special cases that have to be handled specifically, but I'm trying to make the generation of objects as general as possible.

3. Transform the object by calling transformer.transform(createdObject, outputStream):

4. Transform the object again by calling transformer.transform(transformableObject, inputstream).

5. If no exceptions are thrown during transformation, the test is succesfull.

This is essentially what I'm trying to do.

This problem can be easily solved if you are ready to pass around "type" tokens i.e. Class instances to methods. Let's say you want to create a generic "doSomething" method as mentioned in your first post. The generic version would look something along the lines of:

public <T> T doSomething(Object obj, Class<T> klass) {
    T someObject = klass.cast(map.get(obj));
    if(someObject == null) throw new SomeException();
    return someObject;
}

Also, when you instantiate any "generic" object using reflection, all the bets are off (given that you have used introspection and not regular constructs which are subject to compile time checks) and hence it might be a bit misleading to say that you created a "Map<String, String>" because under the hood, it's just a Map instance (given that generics are implemented using type erasure).

So where and how exactly does the map come into it, and what exactly is the question about the map?

~s.o.s~: I can't change the program code itself, well, I can but that is not the problem I'm trying to solve, I don't want to rewrite code just to make the test work. That would take to much effort. The example was just one of many places where similar things are done.

The problem with maps is that some classes that have instances of maps, casts the contents of the map to unkown types (from the tests perspective). When I get the fields of a class using reflection, I know that the field is supposed to be an instance of a map. I don't know the types of the keys or values.

The issue occurs after the object has been generated. The transformation calls the doSomething method at some point, that casts the values in the map to some unknown type.

> I don't know the types of the keys or values

I'm not sure I understand. For a newly created raw map using reflection, there is no way of "retrieving" the type information without querying the actual contents (unless using type tokens). Something like:

Map<Object, Object> m = (Map<Object, Object>) map;
for (Map.Entry<Object, Object> e : m.entrySet()) {
    Object k = e.getKey();
    Object v = e.getValue();
    System.out.println("Type of key: " + k.getClass().getName());
    System.out.println("Type of value: " + v.getClass().getName());
}

It would be easier to help you out if you can hack together a small compilable test program which demonstrates the problem you are facing.

Ahh, frustrating. I solved this but in a ungeneral way.

I guess that the only way to make it general is to perform some kind of analysis of the class that is instansiated to see what the values of the map is going to be cast to before creating the map. Not impossible, but far fetched.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.