Gideon
Gideon

Reputation: 1517

Determine the datatype of an Object's property

I have two similar object in Java / Groovy, lets say:

class a {
    Date creation
}

class a {
    String creation
}

and in my program, there is a switch that determines what object should I use (Groovy code):

def obj
if(/* certain criteria for a */) {
    obj = new package.foo.a()

    // ...
    // Or some other process aside from initialization.
}
else if(/* certain criteria for the another a */) {
    obj = new package.bar.a()

    // ...
    // Or some other process aside from initialization.

}
else {
    obj = null
}

Later in the code, I need to determine the process I should perform based on the type of the property creation:

if(obj.creation instanceof Date) {
    obj.creation = new Date()
}
else if(obj.creation instanceof String) {
    obj.creation = '1995-08-17'
}

The above code doesn't work. Is there someway to do this? Of course I can always do the following if the property's datatype is not obtainable:

if(obj instanceof package.foo.a) {
    obj.creation = new Date()
}
else if(obj instanceof package.bar.a) {
    obj.creation = '1995-08-17'
}

Upvotes: 2

Views: 150

Answers (3)

Emmanuel Rosa
Emmanuel Rosa

Reputation: 9885

Sometimes depending on an object's type in necessary, but it should be avoided because it makes the code more fragile. You could end up with type checking littered all over your code base. In your case, you can delegate the class-specific behaviour to the class itself. Here's an example:

class A {
    Date creation

    void initializeCreationDate() {
        creation = new Date()
    }
}

/* I'm using a different class name to make this
 * example self-contained.
 */
class B {
    String creation

    void initializeCreationDate() {
        creation = '1995-08-17'
    }
}

def obj
def condition = true

if(condition) {
    obj = new A()
} else {
    obj = new B()
}

obj.initializeCreationDate()

In the example, the two classes become responsible for setting their own creation date. This helps keep the code nice and neat.

Using a mixin instead

You can still achieve the same effect even when you're unable to (or do not want to) modify the source code of the two classes. In such a case, you can use a mixin to add the initializeCreationDate() method. Like this:

class A {
    Date creation
}

/* I'm using a different class name to make this
 * example self-contained.
 */
class B {
    String creation
}

class DateInitializer {
    static void initializeCreationDate(A object) {
        object.creation = new Date()
    }

    static void initializeCreationDate(B object) {
        object.creation = '1995-08-17'
    }
}

def obj
def condition = true

if(condition) {
    obj = new A()
} else {
    obj = new B()
}

obj.metaClass.mixin DateInitializer
obj.initializeCreationDate()

Upvotes: 1

hussachai
hussachai

Reputation: 4472

It doesn't work because creation is null. null is not an instance of any objects. You have to use reflection API to get a field type and then use Class.isAssignableFrom() to check type.

if(String.class.isAssignableFrom(a.class.getDeclaredField("creation").getType()){
   ...
}

I edited it to make the code compiles :)

Upvotes: 0

Moishe Lipsker
Moishe Lipsker

Reputation: 3034

You could try getting the class of the object and checking if it has the same class as whichever type you are checking for:

if(obj.creation.getClass().equals(Date.class)) {
    obj.creation = new Date();
}
else if(obj.creation.getClass().equals(String.class)) {
    obj.creation = "1995-08-17";
}

Upvotes: 2

Related Questions