poornerd

my thoughts on programming and other nerdy stuff

How to use Reflection to Document your Data Model based on JPA Annotations

| 0 comments

annotation_reflectionSo using JPA, Hiber­nate or EBeans is cool when you can just anno­tate your Java classes, but haven’t you always wished you could “gen­er­ate” doc­u­men­ta­tion of your data model from the code? Pulling infor­ma­tion of the the JPA / Hiber­nate  and other val­i­da­tion annotations?

Assum­ing you have all those nice Anno­ta­tions in your beans:

@Entity
@Table(name = "project_bills")
public class Bill extends Model {
	
	private static final long serialVersionUID = 1L;

	@Id
	@Column(name="PBI_ID")
	public Long id;
	
	@DoubleFormat
	@Column(name="PBI_BILL_AMOUNT",length=22)
	public Double billAmount;
	
	@Column(name="PBI_BILL_DATE")
	@DateTime(pattern="dd.MM.yyyy")
	public Date billDate;
	
	@Column(name="PBI_BILL_NUMBER",length=10)
	public String billNumber;
	
	@Column(name="PBI_CAN_BILL")
	public Boolean canBill;
	
	@Column(name="PBI_COMMENT",length=65535)
	public String comment;
	
	@Column(name="PBI_PAID_DATE")
	@DateTime(pattern="dd.MM.yyyy")
	public Date paidDate;

 

Here is an exam­ple of how to go about accom­plish­ing that task:

    public static String listEntities(String _package) {
        StringBuffer retval = new StringBuffer();
        Reflections reflections = new Reflections(_package, Play.application().classloader());
        Set<Class<?>> classes = reflections.getTypesAnnotatedWith(javax.persistence.Entity.class);
        for (Class c : classes) {
            retval.append(c.getName() + "\n");
            retval.append(listAnnotations(c.getName()) + "\n\n");
            retval.append(listAttributes(c.getName()) + "\n\n");
        }
        return retval.toString();
    }

    public static String listAnnotations(String _class) {
        StringBuffer retval = new StringBuffer();
        try {
            Annotation[] annotations = Class.forName(_class).getAnnotations();
            if (annotations.length != 0) {
                for (int j = 0; j < annotations.length; j++) {
                    retval.append(annotations[j].toString() + ": " + annotations[j].annotationType() + "\n");
                }
                retval.append("\n");
            }
        } catch (ClassNotFoundException e) {
            System.out.println(e.toString());
            return retval.toString();
        }
        return retval.toString();
    }

    public static String listAttributes(String _class) {
        StringBuffer retval2 = new StringBuffer();
        boolean perstistent = false;
        try {
            for (Field field : Class.forName(_class).getDeclaredFields()) {
                Class type = field.getType();
                String name = field.getName();
                perstistent = false;
                StringBuffer retval = new StringBuffer();
                retval.append("\t" + name + " (" + type + ")\n");
                Annotation[] annotations = field.getDeclaredAnnotations();

                if (annotations.length != 0) {
                    for (int j = 0; j < annotations.length; j++) {
                        retval.append(annotations[j].toString() + ": " + annotations[j].annotationType() + "\n");
                        if (annotations[j].toString().startsWith("@javax.persistence")) {
                            perstistent = true;
                        }
                    }
                    retval.append("\n");
                }
                if (perstistent) {
                    retval2.append(retval);
                }
            }
        } catch (ClassNotFoundException e) {
            System.out.println(e.toString());
            return retval2.toString();
        }
        return retval2.toString();
    }

Which will gen­er­ate some­thing like this:

models.controlling.Bill
@javax.persistence.Table(schema=, uniqueConstraints=[], catalog=, name=project_bills): interface javax.persistence.Table
@javax.persistence.Entity(name=): interface javax.persistence.Entity

	id (class java.lang.Long)
@javax.persistence.Id(): interface javax.persistence.Id
@javax.persistence.Column(insertable=true, scale=0, unique=false, precision=0, columnDefinition=, name=PBI_ID, updatable=true, length=255, nullable=true, table=): interface javax.persistence.Column

	billAmount (class java.lang.Double)
@utils.data.formatters.Formats$DoubleFormat(): interface utils.data.formatters.Formats$DoubleFormat
@javax.persistence.Column(insertable=true, scale=0, unique=false, precision=0, columnDefinition=, name=PBI_BILL_AMOUNT, updatable=true, length=22, nullable=true, table=): interface javax.persistence.Column

	billDate (class java.util.Date)
@javax.persistence.Column(insertable=true, scale=0, unique=false, precision=0, columnDefinition=, name=PBI_BILL_DATE, updatable=true, length=255, nullable=true, table=): interface javax.persistence.Column
@play.data.format.Formats$DateTime(pattern=dd.MM.yyyy): interface play.data.format.Formats$DateTime

	billNumber (class java.lang.String)
@javax.persistence.Column(insertable=true, scale=0, unique=false, precision=0, columnDefinition=, name=PBI_BILL_NUMBER, updatable=true, length=10, nullable=true, table=): interface javax.persistence.Column

Of course this is only the tip of the ice­berg, but you get the idea.

Let me know if you have some good ideas of what other types of doc­u­men­ta­tion can be gen­er­ated from the source code.

If you have read this far, you may as well fol­low me on Twit­ter:

Author: poornerd

Tech­nol­o­gist, Entre­pre­neur, Vision­ary, Pro­gram­mer :: Grad­u­ated from USC (Uni­ver­sity of South­ern Cal­i­for­nia) with a degree in Com­puter Sci­ence. After 10+ years of free­lance con­sult­ing and pro­gram­ming, he co-founded Site­Force AG eBusi­ness Solu­tions in 1999 in Munich (München), Ger­many.

Leave a Reply

Required fields are marked *.