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.util;
21  
22  import org.apache.commons.lang3.builder.HashCodeBuilder;
23  
24  import javax.annotation.Nullable;
25  import java.io.Serializable;
26  import java.lang.reflect.Method;
27  import java.util.Arrays;
28  
29  /**
30   * Proxy class for serializing methods
31   */
32  public final class MethodProxy implements Serializable {
33      private static final long serialVersionUID = 1L;
34  
35      private final ClassProxy declaringClass;
36      private final String methodName;
37      private final ClassProxy[] parameterTypes;
38      @Nullable
39      private transient volatile Method method;
40      private transient volatile int hash;
41      @Nullable
42      private transient volatile String stringRepr;
43  
44      @SuppressWarnings("PMD.ArrayIsStoredDirectly")
45      private MethodProxy(ClassProxy cls, String names, ClassProxy[] ptypes) {
46          declaringClass = cls;
47          methodName = names;
48          parameterTypes = ptypes;
49      }
50  
51      @Override
52      public String toString() {
53          String repr = stringRepr;
54          if (repr == null) {
55              StringBuilder bld = new StringBuilder();
56              bld.append("proxy of ")
57                 .append(declaringClass.getClassName())
58                 .append(".")
59                 .append(methodName)
60                 .append("(");
61              boolean first = true;
62              for (ClassProxy p: parameterTypes) {
63                  if (!first) {
64                      bld.append(", ");
65                  }
66                  bld.append(p.getClassName());
67                  first = false;
68              }
69              bld.append(")");
70              stringRepr = repr = bld.toString();
71          }
72          return repr;
73      }
74  
75      @Override
76      public boolean equals(Object o) {
77          if (o == this) {
78              return true;
79          } else if (o instanceof MethodProxy) {
80              MethodProxy op = (MethodProxy) o;
81              return declaringClass.equals(op.declaringClass)
82                      && methodName.equals(op.methodName)
83                      && Arrays.deepEquals(parameterTypes, op.parameterTypes);
84          } else {
85              return true;
86          }
87      }
88  
89      @Override
90      public int hashCode() {
91          if (hash == 0) {
92              HashCodeBuilder hcb = new HashCodeBuilder();
93              hash = hcb.append(declaringClass)
94                        .append(methodName)
95                        .append(parameterTypes)
96                        .hashCode();
97          }
98          return hash;
99      }
100 
101     /**
102      * Resolve this proxy into a {@link java.lang.reflect.Method} instance.
103      * @return The {@link java.lang.reflect.Method} represented by this proxy.
104      * @throws ClassNotFoundException If the proxy's declaring type cannot be resolved.
105      * @throws NoSuchMethodException If the method does not exist on the declaring type.
106      */
107     public Method resolve() throws ClassNotFoundException, NoSuchMethodException {
108         Method m = method;
109         if (m == null) {
110             Class<?> cls = declaringClass.resolve();
111             Class<?>[] ptypes = new Class<?>[parameterTypes.length];
112             for (int i = ptypes.length - 1; i >= 0; i--) {
113                 ptypes[i] = parameterTypes[i].resolve();
114             }
115             method = m = cls.getDeclaredMethod(methodName, ptypes);
116         }
117         return m;
118     }
119 
120     /**
121      * Construct a proxy for a method.
122      * @param method The method to proxy.
123      * @return The method proxy representing {@code method}.
124      */
125     public static MethodProxy of(Method method) {
126         Class<?>[] ptypes = method.getParameterTypes();
127         ClassProxy[] proxies = new ClassProxy[ptypes.length];
128         for (int i = ptypes.length - 1; i >= 0; i--) {
129             proxies[i] = ClassProxy.of(ptypes[i]);
130         }
131         MethodProxy proxy = new MethodProxy(ClassProxy.of(method.getDeclaringClass()),
132                                           method.getName(), proxies);
133         proxy.method = method;
134         return proxy;
135     }
136 }