You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SimpleInjector.java 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Copyright (c) 2006-2011 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.util;
  23. import java.lang.reflect.Constructor;
  24. import java.lang.reflect.InvocationTargetException;
  25. import java.util.HashMap;
  26. import java.util.Map;
  27. /**
  28. * Facilitates simple injection of parameters into a constructor.
  29. */
  30. public class SimpleInjector {
  31. /** The parent injector, if any. */
  32. private final SimpleInjector parent;
  33. /** A mapping of known classes to the objects that should be injected. */
  34. private final Map<Class<?>, Object> parameters
  35. = new HashMap<Class<?>, Object>();
  36. /**
  37. * Creates a new injector with no parent.
  38. */
  39. public SimpleInjector() {
  40. this(null);
  41. }
  42. /**
  43. * Creates a new injector which will inherit injection parameters from
  44. * the specified parent. Parent graphs must be acyclic.
  45. *
  46. * @param parent The injector to inherit parameters from.
  47. */
  48. public SimpleInjector(final SimpleInjector parent) {
  49. this.parent = parent;
  50. }
  51. /**
  52. * Adds a new injectable object to this injector. If a constructor requires
  53. * an instance of the specified class, it will be given the specified
  54. * object. If an association has already been made for the specified class,
  55. * it will be replaced with the new object.
  56. *
  57. * @param clazz The type of parameter which should be injected
  58. * @param object The value to inject for the parameter
  59. */
  60. public void addParameter(final Class<?> clazz, final Object object) {
  61. parameters.put(clazz, object);
  62. }
  63. /**
  64. * Adds the specified object as an injectable parameter for all of its
  65. * known classes and interface. This is equivalent to calling
  66. * {@link #addParameter(java.lang.Class, java.lang.Object)} for the object's
  67. * class, all superclasses, and all interfaces.
  68. *
  69. * @param object The object to be injected
  70. */
  71. public void addParameter(final Object object) {
  72. // Iterate the object hierarchy up
  73. Class<?> target = object.getClass();
  74. do {
  75. addParameter(target, object);
  76. target = target.getSuperclass();
  77. } while (target != null);
  78. // Add all interfaces
  79. for (Class<?> iface : object.getClass().getInterfaces()) {
  80. addParameter(iface, object);
  81. }
  82. }
  83. /**
  84. * Retrieves a mapping of known injectable types to their corresponding
  85. * values. If this injector was created with a parent, this mapping will
  86. * also include mappings defined in the parent.
  87. *
  88. * @return A map of injectable parameters
  89. */
  90. public Map<Class<?>, Object> getParameters() {
  91. final Map<Class<?>, Object> localParams
  92. = new HashMap<Class<?>, Object>(parameters.size());
  93. if (parent != null) {
  94. localParams.putAll(parent.getParameters());
  95. }
  96. // Note: insert local parameters after so they override parent params.
  97. localParams.putAll(parameters);
  98. return localParams;
  99. }
  100. /**
  101. * Attempts to create a new instance of the specified class by injecting
  102. * parameters into the constructor(s). If no constructors are found which
  103. * can be satisfied by the known parameters, or if all satisfiable
  104. * constructors throw exceptions, an IllegalArgumentException will be
  105. * thrown.
  106. * <p>
  107. * If multiple constructors are available that are satisfiable using the
  108. * known arguments, no guarantee is given as to which will be used.
  109. *
  110. * @param <T> The type of object being instantiated
  111. * @param clazz The class to create an instance of
  112. * @return An instance of the specified class
  113. * @throws IllegalArgumentException If the class could not be instantiated
  114. */
  115. @SuppressWarnings("unchecked")
  116. public <T> T createInstance(final Class<T> clazz) {
  117. final Map<Class<?>, Object> params = getParameters();
  118. Throwable throwable = null;
  119. for (Constructor<?> rawCtor : clazz.getConstructors()) {
  120. final Constructor<T> ctor = (Constructor<T>) rawCtor;
  121. final Object[] args = new Object[ctor.getParameterTypes().length];
  122. int i = 0;
  123. for (Class<?> paramType : ctor.getParameterTypes()) {
  124. if (params.containsKey(paramType)) {
  125. args[i++] = params.get(paramType);
  126. } else {
  127. break;
  128. }
  129. }
  130. if (i == args.length) {
  131. try {
  132. return ctor.newInstance(args);
  133. } catch (IllegalAccessException ex) {
  134. throwable = ex;
  135. } catch (IllegalArgumentException ex) {
  136. throwable = ex;
  137. } catch (InstantiationException ex) {
  138. throwable = ex;
  139. } catch (InvocationTargetException ex) {
  140. throwable = ex;
  141. } catch (LinkageError err) {
  142. throwable = err;
  143. }
  144. }
  145. }
  146. if (throwable == null) {
  147. throw new IllegalArgumentException("No declared constructors "
  148. + "could be satisfied with known parameters");
  149. }
  150. throw new IllegalArgumentException("A satisfiable constructor was "
  151. + "found but threw an exception", throwable);
  152. }
  153. }