/* * Copyright open knowledge GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.openknowledge.cdi.jpa; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import javax.enterprise.event.Observes; import javax.enterprise.inject.Produces; import javax.enterprise.inject.spi.Annotated; import javax.enterprise.inject.spi.AnnotatedConstructor; import javax.enterprise.inject.spi.AnnotatedField; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedParameter; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ProcessAnnotatedType; import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceUnit; import de.openknowledge.cdi.common.spi.DelegatingAnnotatedField; import de.openknowledge.cdi.common.spi.DelegatingAnnotatedMethod; import de.openknowledge.cdi.common.spi.DelegatingAnnotatedParameter; import de.openknowledge.cdi.common.spi.DelegatingAnnotatedType; import de.openknowledge.cdi.common.spi.InjectLiteral; /** * This extension handles the injection of {@link javax.persistence.PersistenceUnit}s and {@link PersistenceContext}s * by adding {@link javax.inject.Inject} * and {@link de.openknowledge.cdi.jpa.PersistenceUnit} or {@link de.openknowledge.cdi.jpa.PersistenceContext} * to according annotated fields and methods. * * @author Arne Limburg - open knowledge GmbH */ public class JpaExtension implements Extension { public <T> void processJpaAnnotations(@Observes ProcessAnnotatedType<T> annotatedTypeEvent) { if (annotatedTypeEvent.getAnnotatedType().isAnnotationPresent(Entity.class) || annotatedTypeEvent.getAnnotatedType().isAnnotationPresent(Embeddable.class)) { annotatedTypeEvent.veto(); // JPA objects are no CDI beans } AnnotatedType<T> annotatedType = annotatedTypeEvent.getAnnotatedType(); if (isJpaAnnotationPresent(annotatedType)) { annotatedTypeEvent.setAnnotatedType(new JpaAnnotatedType<T>(annotatedType)); } } private boolean isJpaAnnotationPresent(AnnotatedType<?> annotatedType) { for (AnnotatedField<?> field : annotatedType.getFields()) { if (isJpaAnnotationPresent(field)) { return true; } } for (AnnotatedConstructor<?> constructor : annotatedType.getConstructors()) { if (isJpaAnnotationPresent(constructor)) { return true; } } for (AnnotatedMethod<?> method : annotatedType.getMethods()) { if (isJpaAnnotationPresent(method)) { return true; } } return false; } private boolean isJpaAnnotationPresent(Annotated annotated) { return annotated.isAnnotationPresent(PersistenceUnit.class) || annotated.isAnnotationPresent(PersistenceContext.class); } private static class JpaAnnotatedType<T> extends DelegatingAnnotatedType<T> { public JpaAnnotatedType(AnnotatedType<T> delegate) { super(delegate); } @Override protected AnnotatedField<? super T> processAnnotatedField(AnnotatedField<? super T> field) { if (field.isAnnotationPresent(PersistenceContext.class)) { return createPersistenceContextField(field, field.getAnnotation(PersistenceContext.class)); } else if (field.isAnnotationPresent(PersistenceUnit.class)) { return createPersistenceUnitField(field, field.getAnnotation(PersistenceUnit.class)); } else { return super.processAnnotatedField(field); } } @Override protected AnnotatedMethod<? super T> processAnnotatedMethod(AnnotatedMethod<? super T> method) { if (method.isAnnotationPresent(PersistenceContext.class)) { return createPersistenceContextMethod(method); } else if (method.isAnnotationPresent(PersistenceUnit.class)) { return createPersistenceUnitMethod(method); } else { return super.processAnnotatedMethod(method); } } @SuppressWarnings("unchecked") private <A> AnnotatedField<A> createPersistenceContextField(AnnotatedField<A> field, PersistenceContext delegate) { DelegatingAnnotatedField<A> delegateField = new DelegatingAnnotatedField<A>((AnnotatedType<A>) this, field); delegateField.removeAnnotation(delegate.annotationType()); delegateField.addAnnotation(new DelegatingPersistenceContext(delegate)); if (!field.isAnnotationPresent(Produces.class)) { delegateField.addAnnotation(new InjectLiteral()); } return delegateField; } @SuppressWarnings("unchecked") private <A> AnnotatedField<A> createPersistenceUnitField(AnnotatedField<A> field, PersistenceUnit delegate) { DelegatingAnnotatedField<A> delegateField = new DelegatingAnnotatedField<A>((AnnotatedType<A>) this, field); delegateField.removeAnnotation(delegate.annotationType()); delegateField.addAnnotation(new DelegatingPersistenceUnit(delegate)); if (!field.isAnnotationPresent(Produces.class)) { delegateField.addAnnotation(new InjectLiteral()); } return delegateField; } @SuppressWarnings("unchecked") private <A> AnnotatedMethod<A> createPersistenceContextMethod(AnnotatedMethod<A> method) { if (method.isAnnotationPresent(Produces.class)) { DelegatingAnnotatedMethod<A> delegatingMethod = new DelegatingAnnotatedMethod<A>((AnnotatedType<A>) this, method); PersistenceContext persistenceContext = method.getAnnotation(PersistenceContext.class); delegatingMethod.removeAnnotation(persistenceContext.annotationType()); delegatingMethod.addAnnotation(new DelegatingPersistenceContext(persistenceContext)); return delegatingMethod; } else { return new PersistenceContextMethod<A>((AnnotatedType<A>) this, method); } } @SuppressWarnings("unchecked") private <A> AnnotatedMethod<A> createPersistenceUnitMethod(AnnotatedMethod<A> method) { if (method.isAnnotationPresent(Produces.class)) { DelegatingAnnotatedMethod<A> delegatingMethod = new DelegatingAnnotatedMethod<A>((AnnotatedType<A>) this, method); PersistenceUnit persistenceUnit = method.getAnnotation(PersistenceUnit.class); delegatingMethod.removeAnnotation(persistenceUnit.annotationType()); delegatingMethod.addAnnotation(new DelegatingPersistenceUnit(persistenceUnit)); return delegatingMethod; } else { return new PersistenceUnitMethod<A>((AnnotatedType<A>) this, method); } } } private static class PersistenceContextMethod<T> extends DelegatingAnnotatedMethod<T> { private PersistenceContext persistenceContext; public PersistenceContextMethod(AnnotatedType<T> declaringType, AnnotatedMethod<T> delegate) { super(declaringType, delegate); persistenceContext = delegate.getAnnotation(PersistenceContext.class); removeAnnotation(persistenceContext.annotationType()); if (!delegate.isAnnotationPresent(Produces.class)) { addAnnotation(new InjectLiteral()); } } protected AnnotatedParameter<T> processAnnotatedParameter(AnnotatedParameter<T> annotatedParameter) { if (EntityManagerFactory.class.isAssignableFrom(toClass(annotatedParameter.getBaseType()))) { return new DelegatingAnnotatedParameter<T>(this, annotatedParameter, createPersistenceContextAnnotation()); } else { return annotatedParameter; } } private DelegatingPersistenceContext createPersistenceContextAnnotation() { return new DelegatingPersistenceContext(persistenceContext); } } private static class PersistenceUnitMethod<T> extends DelegatingAnnotatedMethod<T> { private PersistenceUnit persistenceUnit; public PersistenceUnitMethod(AnnotatedType<T> declaringType, AnnotatedMethod<T> delegate) { super(declaringType, delegate); persistenceUnit = delegate.getAnnotation(PersistenceUnit.class); removeAnnotation(persistenceUnit.annotationType()); if (!delegate.isAnnotationPresent(Produces.class)) { addAnnotation(new InjectLiteral()); } } protected AnnotatedParameter<T> processAnnotatedParameter(AnnotatedParameter<T> annotatedParameter) { if (EntityManager.class.isAssignableFrom(toClass(annotatedParameter.getBaseType()))) { return new DelegatingAnnotatedParameter<T>(this, annotatedParameter, createPersistenceUnitAnnotation()); } else { return annotatedParameter; } } private DelegatingPersistenceUnit createPersistenceUnitAnnotation() { return new DelegatingPersistenceUnit(persistenceUnit); } } private static Class<?> toClass(Type type) { if (type instanceof Class) { return (Class<?>) type; } else if (type instanceof ParameterizedType) { return toClass(((ParameterizedType) type).getRawType()); } else { throw new IllegalArgumentException("Cannot convert type to class: " + type); } } }