-
Notifications
You must be signed in to change notification settings - Fork 79
Expand file tree
/
Copy pathRJavaTools.java
More file actions
195 lines (174 loc) · 6.26 KB
/
RJavaTools.java
File metadata and controls
195 lines (174 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import java.lang.reflect.Method ;
import java.lang.reflect.Constructor ;
/**
* Tools used internally by rJava.
*
* The method lookup code is heavily based on ReflectionTools
* by Romain Francois <[email protected]> licensed under GPL v2 or higher.
*/
public class RJavaTools {
/**
* Attempts to find the best-matching constructor of the class
* o_clazz with the parameter types arg_clazz
*
* @param o_clazz Class to look for a constructor
* @param arg_clazz parameter types
*
* @return <code>null</code> if no constructor is found, or the constructor
*
*/
public static Constructor getConstructor( Class o_clazz, Class[] arg_clazz) throws SecurityException, NoSuchMethodException {
if (o_clazz == null)
return null;
Constructor cons = null ;
/* if there is no argument, try to find a direct match */
if (arg_clazz == null || arg_clazz.length == 0) {
cons = o_clazz.getConstructor( (Class[] )null );
return cons ;
}
/* try to find an exact match */
try {
cons = o_clazz.getConstructor(arg_clazz);
if (cons != null)
return cons ;
} catch (NoSuchMethodException e) {
/* we catch this one because we want to further search */
}
/* ok, no exact match was found - we have to walk through all methods */
cons = null;
Constructor[] candidates = o_clazz.getConstructors();
for (int k = 0; k < candidates.length; k++) {
Constructor c = candidates[k];
Class[] param_clazz = c.getParameterTypes();
if (arg_clazz.length != param_clazz.length) // number of parameters must match
continue;
int n = arg_clazz.length;
boolean ok = true;
for (int i = 0; i < n; i++) {
if (arg_clazz[i] != null && !param_clazz[i].isAssignableFrom(arg_clazz[i])) {
ok = false;
break;
}
}
// it must be the only match so far or more specific than the current match
if (ok && (cons == null || isMoreSpecific(c, cons)))
cons = c;
}
if( cons == null ){
throw new NoSuchMethodException( "No constructor matching the given parameters" ) ;
}
return cons;
}
/**
* Attempts to find the best-matching method of the class <code>o_clazz</code> with the method name <code>name</code> and arguments types defined by <code>arg_clazz</code>.
* The lookup is performed by finding the most specific methods that matches the supplied arguments (see also {@link #isMoreSpecific}).
*
* @param o_clazz class in which to look for the method
* @param name method name
* @param arg_clazz an array of classes defining the types of arguments
*
* @return <code>null</code> if no matching method could be found or the best matching method.
*
* @author Romain Francois <[email protected]>
*/
public static Method getMethod(Class o_clazz, String name, Class[] arg_clazz) {
if (o_clazz == null)
return null;
/* if there is no argument, try to find a direct match */
if (arg_clazz == null || arg_clazz.length == 0) {
try {
Method m = o_clazz.getMethod(name, (Class[])null);
if (m != null)
return m ;
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
// we can bail out here because if there was no match, no method has zero arguments so further search is futile
return null;
}
/* try to find an exact match */
Method met;
try {
met = o_clazz.getMethod(name, arg_clazz);
if (met != null)
return met;
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
/* ok, no exact match was found - we have to walk through all methods */
met = null;
Method[] ml = o_clazz.getMethods();
for (int k = 0; k < ml.length; k++) {
Method m = ml[k];
if (!m.getName().equals(name)) // the name must match
continue;
Class[] param_clazz = m.getParameterTypes();
if (arg_clazz.length != param_clazz.length) // number of parameters must match
continue;
int n = arg_clazz.length;
boolean ok = true;
for (int i = 0; i < n; i++) {
if (arg_clazz[i] != null && !param_clazz[i].isAssignableFrom(arg_clazz[i])) {
ok = false;
break;
}
}
if (ok && (met == null || isMoreSpecific(m, met))) // it must be the only match so far or more specific than the current match
met = m;
}
return met;
}
/**
* Returns <code>true</code> if <code>m1</code> is more specific than <code>m2</code>.
* The measure used is described in the isMoreSpecific( Class[], Class[] ) method
*
* @param m1 method to compare
* @param m2 method to compare
*
* @return <code>true</code> if <code>m1</code> is more specific (in arguments) than <code>m2</code>.
*/
private static boolean isMoreSpecific(Method m1, Method m2) {
Class[] m1_param_clazz = m1.getParameterTypes();
Class[] m2_param_clazz = m2.getParameterTypes();
return isMoreSpecific( m1_param_clazz, m2_param_clazz );
}
/**
* Returns <code>true</code> if <code>cons1</code> is more specific than <code>cons2</code>.
* The measure used is described in the isMoreSpecific( Class[], Class[] ) method
*
* @param cons1 constructor to compare
* @param cons2 constructor to compare
*
* @return <code>true</code> if <code>cons1</code> is more specific (in arguments) than <code>cons2</code>.
*/
private static boolean isMoreSpecific(Constructor cons1, Constructor cons2) {
Class[] cons1_param_clazz = cons1.getParameterTypes();
Class[] cons2_param_clazz = cons2.getParameterTypes();
return isMoreSpecific( cons1_param_clazz, cons2_param_clazz );
}
/**
* Returns <code>true</code> if <code>c1</code> is more specific than <code>c2</code>.
*
* The measure used is the sum of more specific arguments minus the sum of less specific arguments
* which in total must be positive to qualify as more specific.
* (More specific means the argument is a subclass of the other argument).
*
* Both set of classes must have signatures fully compatible in the arguments
* (more precisely incompatible arguments are ignored in the comparison).
*
* @param c1 set of classes to compare
* @param c2 set of classes to compare
*/
private static boolean isMoreSpecific( Class[] c1, Class[] c2){
int n = c1.length ;
int res = 0;
for (int i = 0; i < n; i++)
if( c1[i] != c2[i]) {
if( c1[i].isAssignableFrom(c2[i]))
res--;
else if( c2[i].isAssignableFrom(c2[i]) )
res++;
}
return res > 0;
}
}