Search code examples
javajpametamodel

Metamodel generator for any old class?


I'm finding the JPA metamodel generator functionality really useful for avoiding bugs when column names change. It would be really cool if there was some more general-purpose metamodel generation tool that you could point at any class (or a number of packages) that would generate similar metamodel classes. This could then be used to create compile errors rather than runtime ones when things change:

public class SomeClass {
  public int somePublicProperty;

  public String someStringMethod() {
    ..
  }
}

This might create a metamodel class like:

public class SomeClass_ {
  public static final FieldAttribute<SomeClass,Integer> somePublicProperty;

  public static final MethodAttribute<SomeClass,String> somePublicMethod;
}

where FieldAttribute and MethodAttribute have useful Attribute-like methods to assist with reflection calls (i.e. remove the need to have bare strings):

Object someClassInstance = ... 
Integer value = SomeClass_.somePublicProperty.get( someClassInstance );

// rather than 
Integer value = someClassInstance.getClass().getDeclaredField( "somePublicProperty" ).get( someClassInstance );

Is there anything like this currently available? There's a bit of support in Java 8 now we can do method references, but I'd like something a little bit more metamodel-like if it exists.


Solution

  • I've had this need a few times and I've implemented this: https://github.com/mhagnumdw/bean-info-generator

    Below how you do use this

    If you're using Maven, add it to pom.xml

    <dependency>
        <groupId>io.github.mhagnumdw</groupId>
        <artifactId>bean-info-generator</artifactId>
        <version>0.0.1</version>
        <scope>compile</scope>
    </dependency>
    

    Annotate your class with @GenerateBeanMetaInfo

    import io.github.mhagnumdw.beaninfogenerator.GenerateBeanMetaInfo;
    @GenerateBeanMetaInfo
    public class SomeClass {
        private int someProperty;
    }
    

    When the build run, SomeClass_INFO.java and SomeClass_INFO.class are generated

    public abstract class SomeClass_INFO {
        public static final BeanMetaInfo someProperty = new BeanMetaInfo("someProperty");
    }
    

    Now you can do something like this

    Field field = SomeClass.class.getDeclaredField(SomeClass_INFO.someProperty.getName());
    

    Generate *_INFO.java at development time in Eclipse

    • Right click on the project > Properties
    • Java Compiler > Annotation Processing > Factory path
    • Add two jars: bean-info-generator-0.0.1.jar and javapoet-1.9.0.jar

    I hope it helps!