/*- * #%L * rapidoid-inject * %% * Copyright (C) 2014 - 2018 Nikolche Mihajlovski and contributors * %% * 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. * #L% */ package org.rapidoid.ioc; import org.rapidoid.RapidoidThing; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.ScanPackages; import org.rapidoid.annotation.Since; import org.rapidoid.beany.Metadata; import org.rapidoid.cls.Cls; import org.rapidoid.u.U; import org.rapidoid.util.MscOpts; import javax.annotation.Resource; import javax.inject.Inject; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Collections; import java.util.List; import java.util.Set; @Authors("Nikolche Mihajlovski") @Since("5.1.0") public class ClassMetadata extends RapidoidThing { @SuppressWarnings("unchecked") public static final List<Class<? extends Annotation>> INJECTION_ANNOTATIONS = U.list(Wired.class, Resource.class, Inject.class); public final Class<?> clazz; public final Set<Field> injectableFields; public final Set<Constructor<?>> injectableConstructors; public final Constructor<?> defaultConstructor; public final Set<Class<?>> typesToManage; public final Set<String> packagesToScan; public ClassMetadata(Class<?> clazz) { this.clazz = clazz; this.injectableFields = Collections.synchronizedSet(getInjectableFields(clazz)); this.injectableConstructors = Collections.synchronizedSet(getInjectableConstructors(clazz)); this.defaultConstructor = getDefaultConstructor(clazz); this.typesToManage = Collections.synchronizedSet(getTypesToManage(clazz)); this.packagesToScan = Collections.synchronizedSet(getPackagesToScan(clazz)); } public static Set<Class<?>> getTypesToManage(Class<?> clazz) { Set<Class<?>> types = U.set(); Manage depAnn = Metadata.getAnnotationRecursive(clazz, Manage.class); if (depAnn != null) { Collections.addAll(types, depAnn.value()); } return types; } private Set<String> getPackagesToScan(Class<?> clazz) { ScanPackages scan = Metadata.getAnnotationRecursive(clazz, ScanPackages.class); if (scan != null) { String[] pkgs = scan.value(); U.must(U.notEmpty(pkgs), "@ScanPackages requires a list of packages to scan!"); return U.set(pkgs); } else { return U.set(); } } public static Set<Field> getInjectableFields(Class<?> clazz) { Set<Field> fields = U.set(); for (Class<? extends Annotation> annotation : INJECTION_ANNOTATIONS) { fields.addAll(Cls.getFieldsAnnotated(clazz, annotation)); } if (MscOpts.hasJPA()) { Class<Annotation> javaxPersistenceContext = Cls.get("javax.persistence.PersistenceContext"); List<Field> emFields = Cls.getFieldsAnnotated(clazz, javaxPersistenceContext); for (Field emField : emFields) { U.must(emField.getType().getName().equals("javax.persistence.EntityManager"), "Expected EntityManager type!"); } fields.addAll(emFields); } return fields; } public static Set<Constructor<?>> getInjectableConstructors(Class<?> clazz) { Set<Constructor<?>> constructors = U.set(); for (Constructor<?> constr : clazz.getDeclaredConstructors()) { if (Metadata.hasAny(constr.getAnnotations(), ClassMetadata.INJECTION_ANNOTATIONS)) { constructors.add(constr); } } return constructors; } public static Constructor<?> getDefaultConstructor(Class<?> clazz) { try { return clazz.getDeclaredConstructor(); } catch (NoSuchMethodException e) { return null; } } }