Kaynağa Gözat

Simple constructor dependency injector

Change-Id: I2ffee5b0dd39f47fd2f319d729213d0cde724c65
Reviewed-on: http://gerrit.dmdirc.com/2062
Automatic-Compile: DMDirc Build Manager
Reviewed-by: Greg Holmes <greg@dmdirc.com>
tags/0.7rc1
Chris Smith 13 yıl önce
ebeveyn
işleme
cd5d346a6e
1 değiştirilmiş dosya ile 174 ekleme ve 0 silme
  1. 174
    0
      src/com/dmdirc/util/SimpleInjector.java

+ 174
- 0
src/com/dmdirc/util/SimpleInjector.java Dosyayı Görüntüle

@@ -0,0 +1,174 @@
1
+/*
2
+ * Copyright (c) 2006-2011 Chris Smith, Shane Mc Cormack, Gregory Holmes
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
+
23
+package com.dmdirc.util;
24
+
25
+import java.lang.reflect.Constructor;
26
+import java.lang.reflect.InvocationTargetException;
27
+import java.util.HashMap;
28
+import java.util.Map;
29
+
30
+/**
31
+ * Facilitates simple injection of parameters into a constructor.
32
+ */
33
+public class SimpleInjector {
34
+
35
+    /** The parent injector, if any. */
36
+    private final SimpleInjector parent;
37
+
38
+    /** A mapping of known classes to the objects that should be injected. */
39
+    private final Map<Class<?>, Object> parameters
40
+            = new HashMap<Class<?>, Object>();
41
+
42
+    /**
43
+     * Creates a new injector with no parent.
44
+     */
45
+    public SimpleInjector() {
46
+        this(null);
47
+    }
48
+
49
+    /**
50
+     * Creates a new injector which will inherit injection parameters from
51
+     * the specified parent. Parent graphs must be acyclic.
52
+     *
53
+     * @param parent The injector to inherit parameters from.
54
+     */
55
+    public SimpleInjector(final SimpleInjector parent) {
56
+        this.parent = parent;
57
+    }
58
+
59
+    /**
60
+     * Adds a new injectable object to this injector. If a constructor requires
61
+     * an instance of the specified class, it will be given the specified
62
+     * object. If an association has already been made for the specified class,
63
+     * it will be replaced with the new object.
64
+     *
65
+     * @param clazz The type of parameter which should be injected
66
+     * @param object The value to inject for the parameter
67
+     */
68
+    public void addParameter(final Class<?> clazz, final Object object) {
69
+        parameters.put(clazz, object);
70
+    }
71
+
72
+    /**
73
+     * Adds the specified object as an injectable parameter for all of its
74
+     * known classes and interface. This is equivalent to calling
75
+     * {@link #addParameter(java.lang.Class, java.lang.Object)} for the object's
76
+     * class, all superclasses, and all interfaces.
77
+     *
78
+     * @param object The object to be injected
79
+     */
80
+    public void addParameter(final Object object) {
81
+        // Iterate the object hierarchy up
82
+        Class<?> target = object.getClass();
83
+        do {
84
+            addParameter(target, object);
85
+            target = target.getSuperclass();
86
+        } while (target != null);
87
+
88
+        // Add all interfaces
89
+        for (Class<?> iface : parent.getClass().getInterfaces()) {
90
+            addParameter(iface, object);
91
+        }
92
+    }
93
+
94
+    /**
95
+     * Retrieves a mapping of known injectable types to their corresponding
96
+     * values. If this injector was created with a parent, this mapping will
97
+     * also include mappings defined in the parent.
98
+     *
99
+     * @return A map of injectable parameters
100
+     */
101
+    public Map<Class<?>, Object> getParameters() {
102
+        final Map<Class<?>, Object> localParams
103
+                = new HashMap<Class<?>, Object>(parameters.size());
104
+
105
+        if (parent != null) {
106
+            localParams.putAll(parent.getParameters());
107
+        }
108
+
109
+        // Note: insert local parameters after so they override parent params.
110
+        localParams.putAll(parameters);
111
+
112
+        return localParams;
113
+    }
114
+
115
+    /**
116
+     * Attempts to create a new instance of the specified class by injecting
117
+     * parameters into the constructor(s). If no constructors are found which
118
+     * can be satisfied by the known parameters, or if all satisfiable
119
+     * constructors throw exceptions, an IllegalArgumentException will be
120
+     * thrown.
121
+     * <p>
122
+     * If multiple constructors are available that are satisfiable using the
123
+     * known arguments, no guarantee is given as to which will be used.
124
+     *
125
+     * @param <T> The type of object being instantiated
126
+     * @param clazz The class to create an instance of
127
+     * @return An instance of the specified class
128
+     * @throws IllegalArgumentException If the class could not be instantiated
129
+     */
130
+    @SuppressWarnings("unchecked")
131
+    public <T> T createInstance(final Class<T> clazz) {
132
+        final Map<Class<?>, Object> params = getParameters();
133
+        Throwable throwable = null;
134
+
135
+        for (Constructor<?> rawCtor : clazz.getConstructors()) {
136
+            final Constructor<T> ctor = (Constructor<T>) rawCtor;
137
+            final Object[] args = new Object[ctor.getParameterTypes().length];
138
+
139
+            int i = 0;
140
+            for (Class<?> paramType : ctor.getParameterTypes()) {
141
+                if (params.containsKey(paramType)) {
142
+                    args[i++] = params.get(paramType);
143
+                } else {
144
+                    break;
145
+                }
146
+            }
147
+
148
+            if (i == args.length) {
149
+                try {
150
+                    return ctor.newInstance(args);
151
+                } catch (IllegalAccessException ex) {
152
+                    throwable = ex;
153
+                } catch (IllegalArgumentException ex) {
154
+                    throwable = ex;
155
+                } catch (InstantiationException ex) {
156
+                    throwable = ex;
157
+                } catch (InvocationTargetException ex) {
158
+                    throwable = ex;
159
+                } catch (LinkageError err) {
160
+                    throwable = err;
161
+                }
162
+            }
163
+        }
164
+
165
+        if (throwable == null) {
166
+            throw new IllegalArgumentException("No declared constructors "
167
+                    + "could be satisfied with known parameters");
168
+        }
169
+
170
+        throw new IllegalArgumentException("A satisfiable constructor was "
171
+                + "found but threw an exception", throwable);
172
+    }
173
+
174
+}

Loading…
İptal
Kaydet