View Javadoc

1   /*
2    * Grapht, an open source dependency injector.
3    * Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt)
4    * Copyright 2010-2014 Regents of the University of Minnesota
5    *
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU Lesser General Public License as
8    * published by the Free Software Foundation; either version 2.1 of the
9    * License, or (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14   * details.
15   *
16   * You should have received a copy of the GNU General Public License along with
17   * this program; if not, write to the Free Software Foundation, Inc., 51
18   * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19   */
20  package org.grouplens.grapht.reflect.internal;
21  
22  import org.grouplens.grapht.reflect.InjectionPoint;
23  import org.grouplens.grapht.util.MethodProxy;
24  import org.grouplens.grapht.util.Preconditions;
25  import org.grouplens.grapht.util.Types;
26  
27  import javax.annotation.Nonnull;
28  import javax.annotation.Nullable;
29  import java.io.InvalidObjectException;
30  import java.io.ObjectInputStream;
31  import java.io.ObjectStreamException;
32  import java.io.Serializable;
33  import java.lang.annotation.Annotation;
34  import java.lang.reflect.Method;
35  import java.lang.reflect.Type;
36  import java.util.Collection;
37  
38  /**
39   * SetterInjectionPoint represents an injection point via a setter method.
40   *
41   * @author <a href="http://grouplens.org">GroupLens Research</a>
42   */
43  public class SetterInjectionPoint implements InjectionPoint, Serializable {
44      private static final long serialVersionUID = -1L;
45      // transient because we use a serialization proxy
46      private final transient Method setter;
47      private final transient int parameter;
48      private final transient AnnotationHelper annotations;
49  
50      /**
51       * Create a SetterInjectionPoint that wraps the given setter method.
52       *
53       * @param setter The setter method
54       * @param parameter The parameter index to apply
55       */
56      public SetterInjectionPoint(@Nonnull Method setter, int parameter) {
57          Preconditions.notNull("setter method", setter);
58          Preconditions.inRange(parameter, 0, setter.getParameterTypes().length);
59  
60          this.annotations = new AnnotationHelper(setter.getParameterAnnotations()[parameter]);
61          this.setter = setter;
62          this.parameter = parameter;
63      }
64  
65      /**
66       * @return The setter method wrapped by this injection point
67       */
68      @Override @Nonnull
69      public Method getMember() {
70          return setter;
71      }
72  
73      /**
74       * @return The parameter index of this injection point within the
75       *         setter's parameters
76       */
77      public int getParameterIndex() {
78          return parameter;
79      }
80  
81      @Override
82      public boolean isNullable() {
83          // we'll check both setter and parameter annotations
84          return Types.hasNullableAnnotation(setter.getAnnotations()) ||
85                 Types.hasNullableAnnotation(setter.getParameterAnnotations()[parameter]);
86      }
87  
88      @Override
89      public Type getType() {
90          return Types.box(setter.getGenericParameterTypes()[parameter]);
91      }
92  
93      @Override
94      public Class<?> getErasedType() {
95          return Types.box(setter.getParameterTypes()[parameter]);
96      }
97  
98      @Nullable
99      @Override
100     public Annotation getQualifier() {
101         return annotations.getQualifier();
102     }
103 
104     @Nullable
105     @Override
106     public <A extends Annotation> A getAttribute(Class<A> atype) {
107         return annotations.getAttribute(atype);
108     }
109 
110     @Nonnull
111     @Override
112     public Collection<Annotation> getAttributes() {
113         return annotations.getAttributes();
114     }
115 
116     @Override
117     public boolean equals(Object o) {
118         if (!(o instanceof SetterInjectionPoint)) {
119             return false;
120         }
121         SetterInjectionPoint p = (SetterInjectionPoint) o;
122         return p.setter.equals(setter) && p.parameter == parameter;
123     }
124 
125     @Override
126     public int hashCode() {
127         return setter.hashCode() ^ (37 * 17 * parameter);
128     }
129 
130     @Override
131     public String toString() {
132         // method setFoo(..., @Qual Type argN, ...)
133         StringBuilder sb = new StringBuilder();
134         sb.append("method ")
135           .append(setter.getName())
136           .append("(");
137         if (parameter > 0) {
138             sb.append("..., ");
139         }
140         if (annotations.getQualifier() != null) {
141             sb.append(annotations.getQualifier())
142               .append(" ");
143         }
144         sb.append(setter.getParameterTypes()[parameter].getName())
145           .append(" arg")
146           .append(parameter);
147         if (parameter < setter.getParameterTypes().length) {
148             sb.append(", ...");
149         }
150         sb.append(")");
151 
152         return sb.toString();
153     }
154 
155     private Object writeReplace() {
156         return new SerialProxy(setter, parameter);
157     }
158 
159     private void readObject(ObjectInputStream stream) throws ObjectStreamException {
160         throw new InvalidObjectException("Serialization proxy required");
161     }
162 
163     private static class SerialProxy implements Serializable {
164         private static final long serialVersionUID = 1L;
165         private final MethodProxy method;
166         private final int parameterIndex;
167         public SerialProxy(Method m, int pidx) {
168             method = MethodProxy.of(m);
169             parameterIndex = pidx;
170         }
171 
172         private Object readResolve() throws ObjectStreamException {
173             try {
174                 return new SetterInjectionPoint(method.resolve(), parameterIndex);
175             } catch (ClassNotFoundException e) {
176                 InvalidObjectException ex =
177                         new InvalidObjectException("no class for " + method.toString());
178                 ex.initCause(e);
179                 throw ex;
180             } catch (NoSuchMethodException e) {
181                 InvalidObjectException ex =
182                         new InvalidObjectException("cannot resolve " + method.toString());
183                 ex.initCause(e);
184                 throw ex;
185             }
186         }
187     }
188 }