|
From: Juergen H. <jho...@us...> - 2007-05-21 11:08:24
|
Update of /cvsroot/springframework/spring/tiger/src/org/springframework/orm/jpa/support In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv15358/tiger/src/org/springframework/orm/jpa/support Modified Files: PersistenceAnnotationBeanPostProcessor.java Log Message: consistent use of ConcurrentHashMaps for minimal locking; consistent use of InjectionMetadata; consistent use of "ReflectionUtils.makeAccessible"; avoid double invocation of @PersistenceContext/Unit setter method in case of explicitly specified property value Index: PersistenceAnnotationBeanPostProcessor.java =================================================================== RCS file: /cvsroot/springframework/spring/tiger/src/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** PersistenceAnnotationBeanPostProcessor.java 27 Apr 2007 14:33:51 -0000 1.13 --- PersistenceAnnotationBeanPostProcessor.java 21 May 2007 11:08:20 -0000 1.14 *************** *** 18,33 **** import java.beans.PropertyDescriptor; - import java.lang.reflect.AccessibleObject; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; - import java.lang.reflect.Modifier; - import java.util.HashMap; - import java.util.LinkedList; - import java.util.List; import java.util.Map; import java.util.Properties; import javax.naming.NamingException; --- 18,28 ---- import java.beans.PropertyDescriptor; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.Map; import java.util.Properties; + import java.util.concurrent.ConcurrentHashMap; import javax.naming.NamingException; *************** *** 39,44 **** --- 34,41 ---- import javax.persistence.PersistenceUnit; + import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValues; + import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; *************** *** 46,49 **** --- 43,47 ---- import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; + import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor; import org.springframework.jndi.JndiLocatorSupport; *************** *** 159,164 **** private ListableBeanFactory beanFactory; ! private final Map<Class<?>, List<AnnotatedMember>> annotationMetadataCache = ! new HashMap<Class<?>, List<AnnotatedMember>>(); --- 157,162 ---- private ListableBeanFactory beanFactory; ! private final Map<Class<?>, InjectionMetadata> injectionMetadataCache = ! new ConcurrentHashMap<Class<?>, InjectionMetadata>(); *************** *** 268,274 **** public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { ! List<AnnotatedMember> metadata = findAnnotationMetadata(bean.getClass()); ! for (AnnotatedMember member : metadata) { ! member.inject(bean); } return true; --- 266,275 ---- public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { ! InjectionMetadata metadata = findPersistenceMetadata(bean.getClass()); ! try { ! metadata.injectFields(bean); ! } ! catch (Throwable ex) { ! throw new BeanCreationException(beanName, "Injection of persistence fields failed", ex); } return true; *************** *** 278,281 **** --- 279,289 ---- PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { + InjectionMetadata metadata = findPersistenceMetadata(bean.getClass()); + try { + metadata.injectMethods(bean, pvs); + } + catch (Throwable ex) { + throw new BeanCreationException(beanName, "Injection of persistence methods failed", ex); + } return pvs; } *************** *** 290,347 **** ! private List<AnnotatedMember> findAnnotationMetadata(Class clazz) { ! synchronized (this.annotationMetadataCache) { ! List<AnnotatedMember> metadata = this.annotationMetadataCache.get(clazz); ! if (metadata == null) { ! final List<AnnotatedMember> newMetadata = new LinkedList<AnnotatedMember>(); ! ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { ! public void doWith(Field field) { ! addIfPresent(newMetadata, field); ! } ! }); ! ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { ! public void doWith(Method method) { ! addIfPresent(newMetadata, method); ! } ! }); ! metadata = newMetadata; ! this.annotationMetadataCache.put(clazz, metadata); ! } ! return metadata; ! } ! } ! ! private void addIfPresent(List<AnnotatedMember> metadata, Member member) { ! AnnotatedElement ae = (AnnotatedElement) member; ! PersistenceContext pc = ae.getAnnotation(PersistenceContext.class); ! PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class); ! if (pc != null) { ! if (pu != null) { ! throw new IllegalStateException( ! "Method may only be annotated with either @PersistenceContext or @PersistenceUnit, not both"); ! } ! if (member instanceof Method && ((Method) member).getParameterTypes().length != 1) { ! throw new IllegalStateException("PersistenceContext annotation requires a single-arg method: " + member); ! } ! Properties properties = null; ! PersistenceProperty[] pps = pc.properties(); ! if (!ObjectUtils.isEmpty(pps)) { ! properties = new Properties(); ! for (int i = 0; i < pps.length; i++) { ! PersistenceProperty pp = pps[i]; ! properties.setProperty(pp.name(), pp.value()); } } - metadata.add(new AnnotatedMember(member, pc.unitName(), pc.type(), properties)); - } - else if (pu != null) { - if (member instanceof Method && ((Method) member).getParameterTypes().length != 1) { - throw new IllegalStateException("PersistenceUnit annotation requires a single-arg method: " + member); - } - metadata.add(new AnnotatedMember(member, pu.unitName())); } } - /** * Return a specified persistence unit for the given unit name, --- 298,339 ---- ! private InjectionMetadata findPersistenceMetadata(Class clazz) { ! // Quick check on the concurrent map first, with minimal locking. ! InjectionMetadata metadata = this.injectionMetadataCache.get(clazz); ! if (metadata == null) { ! synchronized (this.injectionMetadataCache) { ! metadata = this.injectionMetadataCache.get(clazz); ! if (metadata == null) { ! final InjectionMetadata newMetadata = new InjectionMetadata(); ! ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { ! public void doWith(Field field) { ! PersistenceContext pc = field.getAnnotation(PersistenceContext.class); ! PersistenceUnit pu = field.getAnnotation(PersistenceUnit.class); ! if (pc != null || pu != null) { ! newMetadata.addInjectedField(new PersistenceElement(field, null)); ! } ! } ! }); ! ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { ! public void doWith(Method method) { ! PersistenceContext pc = method.getAnnotation(PersistenceContext.class); ! PersistenceUnit pu = method.getAnnotation(PersistenceUnit.class); ! if (pc != null || pu != null) { ! if (method.getParameterTypes().length != 1) { ! throw new IllegalStateException("Persistence annotation requires a single-arg method: " + method); ! } ! PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); ! newMetadata.addInjectedMethod(new PersistenceElement(method, pd)); ! } ! } ! }); ! metadata = newMetadata; ! this.injectionMetadataCache.put(clazz, metadata); } } } + return metadata; } /** * Return a specified persistence unit for the given unit name, *************** *** 458,537 **** * or setter method. */ ! private class AnnotatedMember { ! ! private final Member member; private final String unitName; ! private final PersistenceContextType type; ! ! private final Properties properties; ! ! public AnnotatedMember(Member member, String unitName) { ! this(member, unitName, null, null); ! } ! ! public AnnotatedMember(Member member, String unitName, PersistenceContextType type, Properties properties) { ! this.member = member; ! this.unitName = unitName; ! this.type = type; ! this.properties = properties; ! // Validate member type ! Class<?> memberType = getMemberType(); ! if (!(EntityManagerFactory.class.isAssignableFrom(memberType) || ! EntityManager.class.isAssignableFrom(memberType))) { ! throw new IllegalArgumentException("Cannot inject " + member + ": not a supported JPA type"); ! } ! } ! public void inject(Object instance) { ! Object value = resolve(); ! try { ! if (!Modifier.isPublic(this.member.getModifiers()) || ! !Modifier.isPublic(this.member.getDeclaringClass().getModifiers())) { ! ((AccessibleObject) this.member).setAccessible(true); ! } ! if (this.member instanceof Field) { ! ((Field) this.member).set(instance, value); ! } ! else if (this.member instanceof Method) { ! ((Method) this.member).invoke(instance, value); ! } ! else { ! throw new IllegalArgumentException("Cannot inject unknown AccessibleObject type " + this.member); } ! } ! catch (IllegalAccessException ex) { ! throw new IllegalArgumentException("Cannot inject member " + this.member, ex); ! } ! catch (InvocationTargetException ex) { ! // Method threw an exception ! throw new IllegalArgumentException("Attempt to inject setter method " + this.member + ! " resulted in an exception", ex); ! } ! } ! ! /** ! * Return the type of the member, whether it's a field or a method. ! */ ! public Class<?> getMemberType() { ! if (this.member instanceof Field) { ! return ((Field) member).getType(); ! } ! else if (this.member instanceof Method) { ! Method setter = (Method) this.member; ! if (setter.getParameterTypes().length != 1) { ! throw new IllegalArgumentException( ! "Supposed setter [" + this.member + "] must have 1 argument, not " + ! setter.getParameterTypes().length); } ! return setter.getParameterTypes()[0]; } else { ! throw new IllegalArgumentException( ! "Unknown AccessibleObject type [" + this.member.getClass() + ! "]; can only inject setter methods and fields"); } } --- 450,490 ---- * or setter method. */ ! private class PersistenceElement extends InjectionMetadata.InjectedElement { private final String unitName; ! private PersistenceContextType type; ! private Properties properties; ! public PersistenceElement(Member member, PropertyDescriptor pd) { ! super(member, pd); ! AnnotatedElement ae = (AnnotatedElement) member; ! PersistenceContext pc = ae.getAnnotation(PersistenceContext.class); ! PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class); ! Class resourceType = EntityManager.class; ! if (pc != null) { ! if (pu != null) { ! throw new IllegalStateException("Memeber may only be annotated with either " + ! "@PersistenceContext or @PersistenceUnit, not both: " + member); } ! Properties properties = null; ! PersistenceProperty[] pps = pc.properties(); ! if (!ObjectUtils.isEmpty(pps)) { ! properties = new Properties(); ! for (int i = 0; i < pps.length; i++) { ! PersistenceProperty pp = pps[i]; ! properties.setProperty(pp.name(), pp.value()); ! } } ! this.unitName = pc.unitName(); ! this.type = pc.type(); ! this.properties = properties; } else { ! resourceType = EntityManagerFactory.class; ! this.unitName = pu.unitName(); } + checkResourceType(resourceType); } *************** *** 539,561 **** * Resolve the object against the application context. */ ! private Object resolve() { // Resolves to EntityManagerFactory or EntityManager. ! if (EntityManagerFactory.class.isAssignableFrom(getMemberType())) { ! EntityManagerFactory emf = resolveEntityManagerFactory(); ! if (!getMemberType().isInstance(emf)) { ! throw new IllegalArgumentException("Cannot inject [" + this.member + ! "] with EntityManagerFactory [" + emf + "]: type mismatch"); ! } ! return emf; } else { ! // OK, so we need an EntityManager... ! EntityManager em = (this.type == PersistenceContextType.EXTENDED ? ! resolveExtendedEntityManager() : resolveEntityManager()); ! if (!getMemberType().isInstance(em)) { ! throw new IllegalArgumentException("Cannot inject [" + this.member + ! "] with EntityManager [" + em + "]: type mismatch"); ! } ! return em; } } --- 492,504 ---- * Resolve the object against the application context. */ ! protected Object getResourceToInject() { // Resolves to EntityManagerFactory or EntityManager. ! if (this.type != null) { ! return (this.type == PersistenceContextType.EXTENDED ? ! resolveExtendedEntityManager() : resolveEntityManager()); } else { ! // OK, so we need an EntityManagerFactory... ! return resolveEntityManagerFactory(); } } *************** *** 591,595 **** else { // Create EntityManager based on the field's type. ! em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties, getMemberType()); } } --- 534,538 ---- else { // Create EntityManager based on the field's type. ! em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties, getResourceType()); } } |