Package com.spaceprogram.simplejpa

Source Code of com.spaceprogram.simplejpa.AnnotationManager$ClassMethodEntry

package com.spaceprogram.simplejpa;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceException;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Transient;

/**
* User: treeder
* Date: Mar 22, 2008
* Time: 11:39:54 PM
*/
public class AnnotationManager {

    private static Logger logger = Logger.getLogger(AnnotationManager.class.getName());

    // todo: implement EntityListeners for timestamps
    private Map<String, AnnotationInfo> annotationMap = new HashMap<String, AnnotationInfo>();
    private Map<String, AnnotationInfo> discriminatorMap = new HashMap<String, AnnotationInfo>();
    private SimpleJPAConfig config;

    public AnnotationManager(SimpleJPAConfig config) {
        this.config = config;
    }

    public AnnotationInfo getAnnotationInfo(Object o) {
        Class<?> c = getUnwrappedClass(o.getClass());
        AnnotationInfo ai = getAnnotationInfo(c);
        return ai;
    }

    private Class<?> getUnwrappedClass(Class<? extends Object> class1) {
        Class<?> result = class1;

        while (null != result && result.getClass().getSimpleName().contains("$$EnhancerBy"))
            result = result.getSuperclass();

        return result;
    }

    public Map<String, AnnotationInfo> getAnnotationMap() {
        return annotationMap;
    }


    public AnnotationInfo getAnnotationInfo(Class c) {
        c = stripEnhancerClass(c);
        AnnotationInfo ai = getAnnotationInfo(c.getName());
        if (ai == null) {
            ai = putAnnotationInfo(c);
        }
        return ai;
    }

    private AnnotationInfo getAnnotationInfo(String className) {
        AnnotationInfo ai = getAnnotationMap().get(className);
        return ai;
    }

    /**
     * This strips the cglib class name out of the enhanced classes.
     *
     * @param c
     * @return
     */
    public static Class stripEnhancerClass(Class c) {
        String className = c.getName();
        className = stripEnhancerClass(className);
        if(className.equals(c.getName())){
            // no change, did this to fix groovy issue
            return c;
        } else {
            c = getClass(className, c.getClassLoader());
        }
        return c;
    }

    public static String stripEnhancerClass(String className) {
        int enhancedIndex = className.indexOf("$$EnhancerByCGLIB");
        if (enhancedIndex != -1) {
            className = className.substring(0, enhancedIndex);
        }
        return className;
    }


    /**
     *
     * @param obClass
     * @param classLoader pass in null if you want to use the current threads classloader only
     * @return
     */
    public static Class getClass(String obClass, ClassLoader classLoader) {
        try {
            Class c = null;
            try {
                c = Class.forName(obClass, true, Thread.currentThread().getContextClassLoader());
            } catch (ClassNotFoundException e) {
                try {
                    c = Class.forName(obClass);
                } catch (ClassNotFoundException e1) {
//                    e1.printStackTrace();
//                    System.out.println("THIRD LEVEL CLASS LODER");
//                    c = obClass.getClass().getClassLoader().loadClass(obClass);
                    if(classLoader == null){
                        throw e1;
                    } else {
                        c = classLoader.loadClass(obClass);
                    }
                }
            }
            return c;
        } catch (ClassNotFoundException e) {
            throw new PersistenceException(e);
        }
    }

    /**
     * Gets all the annotation info for a particular class and puts it in our annotation info cache.
     *
     * @param c
     * @return
     */
    public AnnotationInfo putAnnotationInfo(Class c) {
        {
            Entity entity = (Entity) c.getAnnotation(Entity.class);
            if(entity == null){
                throw new PersistenceException("Class not marked as an @Entity: " + c.getName());
            }
        }
        AnnotationInfo ai = new AnnotationInfo();
        ai.setClassAnnotations(c.getAnnotations());
        ai.setMainClass(c);
        Class superClass = c;
        Class rootClass = null;
        while ((superClass = superClass.getSuperclass()) != null) {
            MappedSuperclass mappedSuperclass = (MappedSuperclass) superClass.getAnnotation(MappedSuperclass.class);
            Entity entity = (Entity) superClass.getAnnotation(Entity.class);
            Inheritance inheritance = (Inheritance) superClass.getAnnotation(Inheritance.class);
            if (mappedSuperclass != null || entity != null) {
                putProperties(ai, superClass);
                putMethods(ai, superClass);
                if (entity != null) {
                    rootClass = superClass;
                }
                putEntityListeners(ai, superClass);
            }
        }
        if (rootClass != null) {
            ai.setRootClass(rootClass);
            DiscriminatorValue dv = (DiscriminatorValue) c.getAnnotation(DiscriminatorValue.class);
            String discriminatorValue;
            if (dv != null) {
                discriminatorValue = dv.value();
                if (discriminatorValue == null) {
                    throw new PersistenceException("You must specify a value= for @DiscriminatorValue on " + c.getName());
                }
            } else {
                discriminatorValue = c.getSimpleName();
            }
            ai.setDiscriminatorValue(discriminatorValue);
            discriminatorMap.put(discriminatorValue, ai);
        } else {
            ai.setRootClass(c);
        }
        putTableDeclaration(ai, c);
        putProperties(ai, c);
        putMethods(ai, c);
        if (ai.getIdMethod() == null) {
            throw new PersistenceException("No ID method specified for: " + c.getName());
        }
        putEntityListeners(ai, c);

        getAnnotationMap().put(c.getName(), ai);
        return ai;
    }

    private void putMethods(AnnotationInfo ai, Class c) {
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
//            logger.fine("method=" + method.getName());
            String methodName = method.getName();
            if (!methodName.startsWith("get")) continue;
//            System.out.println("method=" + methodName);
            if (config.isGroovyBeans() && (methodName.equals("getProperty") || methodName.equals("getMetaClass")))
                continue;
            Transient transientM = method.getAnnotation(Transient.class);
            if (transientM != null) continue; // we don't save this one
            ai.addGetter(method);
        }
    }


    /**
     * For field based annotations.
     * TODO add OneToOne and ManyToOne support
     *
     * @param ai
     * @param c
     */
    private void putProperties(AnnotationInfo ai, Class c) {
        for (Field field : c.getDeclaredFields()) {
            parseProperty(ai, c, field);
        }
    }

    private void parseProperty(AnnotationInfo ai, Class c, Field field) {
        // TODO add support for OneToOne
        if (!field.isAnnotationPresent(Transient.class) && (field.isAnnotationPresent(ManyToMany.class) || field.isAnnotationPresent(OneToMany.class) || field.isAnnotationPresent(ManyToOne.class) || field.isAnnotationPresent(Id.class))) {
            ai.addField(field);
        }
    }

    private void putTableDeclaration(AnnotationInfo ai, Class<?> c)
  {
      Table table = c.getAnnotation(Table.class);
      if(table != null)
      {
        if(table.name() == null)
          throw new PersistenceException("You must specify a name= for @Table on " + c.getName());
       
        ai.setDomainName(table.name());
      }
  }


    private void putEntityListeners(AnnotationInfo ai, Class c) {
        EntityListeners listeners = (EntityListeners) c.getAnnotation(EntityListeners.class);
        if (listeners != null) {
            logger.fine("Found EntityListeners for " + c + " - " + listeners);
            putEntityListeners(ai, listeners);
        }
    }

    @SuppressWarnings("unchecked")
    private void putEntityListeners(AnnotationInfo ai, EntityListeners entityListeners) {
        Class[] entityListenerClasses = entityListeners.value();
        if (entityListenerClasses == null) return;

        Map<Class, List<ClassMethodEntry>> listeners = ai.getEntityListeners();

        List<Class<? extends Annotation>> annotations = Arrays.asList(
                PrePersist.class,
                PreUpdate.class,
                PreRemove.class,
                PostLoad.class,
                PostPersist.class,
                PostUpdate.class,
                PostRemove.class
        );
        // TODO: More than one listener per event cannot be handled like this...

        for (Class clazz : entityListenerClasses) {
//            System.out.println("class=" + clazz);
            for (Method method : clazz.getMethods()) {
//                System.out.println("method=" + method.getName());
                for (Class<? extends Annotation> annotationClass : annotations) {
                    Annotation annotation = method.getAnnotation(annotationClass);
                    addListener(listeners, clazz, method, annotation, annotationClass);
                }

            }
        }
    }

    private void addListener(Map<Class, List<ClassMethodEntry>> listeners, Class clazz, Method method, java.lang.annotation.Annotation annotation, Class<? extends Annotation> annotationClass) {
        if (annotation != null) {
            List<ClassMethodEntry> entryList = listeners.get(annotationClass);
            if (entryList == null) {
                entryList = new ArrayList<ClassMethodEntry>();
                listeners.put(annotationClass, entryList);
            }
//            System.out.println("adding " + method + " for " + annotation);
            entryList.add(new ClassMethodEntry(clazz, method));
        }
    }

    public AnnotationInfo getAnnotationInfoByDiscriminator(String discriminatorValue) {
        return discriminatorMap.get(discriminatorValue);
    }

    public class ClassMethodEntry {
        private Class clazz;
        private Method method;

        public ClassMethodEntry(Class clazz, Method method) {
            this.clazz = clazz;
            this.method = method;
        }

        public void invoke(Object... args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
            this.method.invoke(clazz.newInstance(), args);
        }
    }
}
TOP

Related Classes of com.spaceprogram.simplejpa.AnnotationManager$ClassMethodEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.