/* * Copyright 2011, Mysema Ltd * * 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 com.mysema.query.codegen; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; /** * AbstractModule provides a base class for annotation based dependency injection * * @author tiwe * */ public abstract class AbstractModule { private final Map, Object> instances = new HashMap, Object>(); private final Map, Class> bindings = new HashMap, Class>(); private final Map namedInstances = new HashMap(); private final Map> namedBindings = new HashMap>(); public AbstractModule() { configure(); } public final AbstractModule bind(Class clazz) { if (clazz.isInterface()) { throw new IllegalArgumentException("Interfaces can't be instantiated"); } bind(clazz, clazz); return this; } public final AbstractModule bind(String name, Class implementation) { namedBindings.put(name, implementation); return this; } public final AbstractModule bind(String name, T implementation) { namedInstances.put(name, implementation); return this; } public final AbstractModule bindInstance(String name, Class implementation) { namedInstances.put(name, implementation); return this; } public final AbstractModule bind(Class iface, Class implementation) { bindings.put(iface, implementation); return this; } public final AbstractModule bind(Class iface, T implementation) { instances.put(iface, implementation); return this; } protected abstract void configure(); @SuppressWarnings("unchecked") public final T get(Class iface) { if (instances.containsKey(iface)) { return (T)instances.get(iface); } else if (bindings.containsKey(iface)) { Class implementation = bindings.get(iface); T instance = (T)createInstance(implementation); instances.put(iface, instance); return instance; } else { throw new IllegalArgumentException(iface.getName() + " is not registered"); } } @SuppressWarnings("unchecked") public final T get(Class iface, String name) { if (namedInstances.containsKey(name)) { return (T)namedInstances.get(name); } else if (namedBindings.containsKey(name)) { Class implementation = namedBindings.get(name); if (implementation != null) { T instance = (T)createInstance(implementation); namedInstances.put(name, instance); return instance; } else { return null; } } else { throw new IllegalArgumentException(iface.getName() + " " + name + " is not registered"); } } @SuppressWarnings("unchecked") private T createInstance(Class implementation) { Constructor constructor = null; for (Constructor c : implementation.getConstructors()) { if (c.getAnnotation(Inject.class) != null) { constructor = c; break; } } // fallback to default constructor if (constructor == null) { try { constructor = implementation.getConstructor(); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } if (constructor != null) { Object[] args = new Object[constructor.getParameterTypes().length]; for (int i = 0; i < constructor.getParameterTypes().length; i++) { Named named = getNamedAnnotation(constructor.getParameterAnnotations()[i]); if (named != null) { args[i] = get(constructor.getParameterTypes()[i], named.value()); } else { args[i] = get(constructor.getParameterTypes()[i]); } } try { return (T) constructor.newInstance(args); // TODO : populate fields as well?!? } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } else { throw new IllegalArgumentException("Got no annotated constructor for " + implementation.getName()); } } private Named getNamedAnnotation(Annotation[] annotations) { for (Annotation annotation : annotations) { if (annotation.annotationType().equals(Named.class)) { return (Named)annotation; } } return null; } }