5

I'm having an issue with reflection. I decided I wanted to create a SQL Query Generator using reflection. I created my own annotations to determine what classes can be used, what attributes can be stored ect. The code works as I want it to, however the issue lyes in using this project as a dependency in others.

I have another project using OJDBC and im trying to use my library to generate the Queries based on class. However when I pass a class from my ojdbc project there is a loss of all class information, the class is appearing as java.lang.Class and even the annotaion information is lost. Does anyone know why this is happening?

private static <T> void appendTableName(Class<T> cls) throws NotStorableException {
    Storable storable = cls.getAnnotation(Storable.class);
    String tableName = null;
    if (storable != null) {
        if ((tableName = storable.tableName()).isEmpty())
            tableName = cls.getSimpleName();
    } else {    
        throw new NotStorableException(
                "The class you are trying to persist must declare the Storable annotaion");
    }
    createStatement.append(tableName.toUpperCase());
}

The cls.getAnnotation(Storable.class) is losing the information when the following class is passed to it

package com.fdm.ojdbc;

import com.fdm.QueryBuilder.annotations.PrimaryKey;
import com.fdm.QueryBuilder.annotations.Storable;

@Storable(tableName="ANIMALS")
public class Animal {

@PrimaryKey
private String name;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

The animal class is in the ojdbc project and the appendTableName method belongs to my query builder. I have tried generating the querybuilder project into a jar and use maven install to add it to my repository and still no luck.

Thanks for the quick reply, however this isn't problem as the Annotation I created has Retention set to Runtime see below.

package com.fdm.QueryBuilder.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = { ElementType.TYPE })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Storable {
    public String tableName() default "";
}

My annotation is set to runtime yet the class information is still being lost.

billy.mccarthy
  • 122
  • 1
  • 11
  • The code you posted should work. That is, the cause lies elsewhere. Are you absolutely sure the class object being passed corresponds to a class with this annotation? (And not, for instance, some runtime generated subclass?) Are you sure the class has been defined from a source that has that annotation? (You aren't running with an old version of the class that doesn't have the annotation yet, are you?) – meriton May 20 '15 at 11:05
  • No, its running with the correct version of the annotation and im not subtyping at the moment. The class throws no compilation errors and correctly references the annotation. The annotation is packed in a jar that has been added to the project via maven dependencies. – billy.mccarthy May 21 '15 at 13:17
  • 1
    ... and you are sure the annotation class is available on the runtime class path? (You can verify this by checking that `Class.forName("com.whatever.Storable")` does not throw an exception) – meriton May 21 '15 at 13:47

1 Answers1

5

When you want an annotation which is usable at runtime you need to add an annotation to it.

@Retention(RetentionPolicy.RUNTIME)
public @interface Storable {

Without this, the annotation is not visible at runtime.

For more information, here is the source for this annotation.

/**
 * Indicates how long annotations with the annotated type are to
 * be retained.  If no Retention annotation is present on
 * an annotation type declaration, the retention policy defaults to
 * {@code RetentionPolicy.CLASS}.
 *
 * <p>A Retention meta-annotation has effect only if the
 * meta-annotated type is used directly for annotation.  It has no
 * effect if the meta-annotated type is used as a member type in
 * another annotation type.
 *
 * @author  Joshua Bloch
 * @since 1.5
 * @jls 9.6.3.2 @Retention
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I'm not entirely sure what I was going wrong as I made no changes to the code and now it seems to run fine. Thanks for the input. – billy.mccarthy May 27 '15 at 13:18