Skip to content

Commit 5e33b07

Browse files
committed
Rework ClassMatcher-s (used for veto) to take on account indirect inheritance
1 parent 8af0fd4 commit 5e33b07

File tree

16 files changed

+482
-315
lines changed

16 files changed

+482
-315
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ You have to add the following configuration to enable build-time instrumentation
3535
<dependency>
3636
<groupId>net.tascalate.javaflow</groupId>
3737
<artifactId>net.tascalate.javaflow.extras</artifactId>
38-
<version>2.4.1</version>
38+
<version>2.4.2</version>
3939
</dependency>
4040
...
4141
</dependencies>

net.tascalate.javaflow.providers.asm3/src/main/java/org/apache/commons/javaflow/providers/asm3/PartialResourceTransformationFactory.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2013-2019 Valery Silaev (http://vsilaev.com)
2+
* Copyright 2013-2021 Valery Silaev (http://vsilaev.com)
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
1919

2020
import org.apache.commons.javaflow.spi.Cache;
2121
import org.apache.commons.javaflow.spi.ClassMatcher;
22-
import org.apache.commons.javaflow.spi.ClassMatchers;
2322
import org.apache.commons.javaflow.spi.ResourceLoader;
2423
import org.apache.commons.javaflow.spi.ResourceTransformer;
2524
import org.apache.commons.javaflow.spi.VetoableResourceLoader;
@@ -49,7 +48,7 @@ static ClassMatcher createVeto(ResourceLoader resourceLoader) {
4948
throw new RuntimeException(ex);
5049
}
5150
} else {
52-
return ClassMatchers.MATCH_NONE;
51+
return ClassMatcher.MATCH_NONE;
5352
}
5453
}
5554

net.tascalate.javaflow.providers.asm4/src/main/java/org/apache/commons/javaflow/providers/asm4/PartialResourceTransformationFactory.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2013-2019 Valery Silaev (http://vsilaev.com)
2+
* Copyright 2013-2021 Valery Silaev (http://vsilaev.com)
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
1919

2020
import org.apache.commons.javaflow.spi.Cache;
2121
import org.apache.commons.javaflow.spi.ClassMatcher;
22-
import org.apache.commons.javaflow.spi.ClassMatchers;
2322
import org.apache.commons.javaflow.spi.ResourceLoader;
2423
import org.apache.commons.javaflow.spi.ResourceTransformer;
2524
import org.apache.commons.javaflow.spi.VetoableResourceLoader;
@@ -49,7 +48,7 @@ static ClassMatcher createVeto(ResourceLoader resourceLoader) {
4948
throw new RuntimeException(ex);
5049
}
5150
} else {
52-
return ClassMatchers.MATCH_NONE;
51+
return ClassMatcher.MATCH_NONE;
5352
}
5453
}
5554

net.tascalate.javaflow.providers.asm5/src/main/java/org/apache/commons/javaflow/providers/asm5/PartialResourceTransformationFactory.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2013-2019 Valery Silaev (http://vsilaev.com)
2+
* Copyright 2013-2021 Valery Silaev (http://vsilaev.com)
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
1919

2020
import org.apache.commons.javaflow.spi.Cache;
2121
import org.apache.commons.javaflow.spi.ClassMatcher;
22-
import org.apache.commons.javaflow.spi.ClassMatchers;
2322
import org.apache.commons.javaflow.spi.ResourceLoader;
2423
import org.apache.commons.javaflow.spi.ResourceTransformer;
2524
import org.apache.commons.javaflow.spi.VetoableResourceLoader;
@@ -49,7 +48,7 @@ static ClassMatcher createVeto(ResourceLoader resourceLoader) {
4948
throw new RuntimeException(ex);
5049
}
5150
} else {
52-
return ClassMatchers.MATCH_NONE;
51+
return ClassMatcher.MATCH_NONE;
5352
}
5453
}
5554

net.tascalate.javaflow.providers.asmx/src/main/java/org/apache/commons/javaflow/providers/asmx/PartialResourceTransformationFactory.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import org.apache.commons.javaflow.spi.Cache;
2121
import org.apache.commons.javaflow.spi.ClassMatcher;
22-
import org.apache.commons.javaflow.spi.ClassMatchers;
2322
import org.apache.commons.javaflow.spi.ResourceLoader;
2423
import org.apache.commons.javaflow.spi.ResourceTransformer;
2524
import org.apache.commons.javaflow.spi.VetoableResourceLoader;
@@ -68,7 +67,7 @@ static ClassMatcher createVeto(ResourceLoader resourceLoader) {
6867
throw new RuntimeException(ex);
6968
}
7069
} else {
71-
return ClassMatchers.MATCH_NONE;
70+
return ClassMatcher.MATCH_NONE;
7271
}
7372
}
7473

net.tascalate.javaflow.spi/src/main/java/org/apache/commons/javaflow/spi/ClassHeaderReader.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,40 @@ String getClassName() {
211211
// this_class is just after the access_flags field (using 2 bytes).
212212
return readClass(header + 2, new char[maxStringLength]);
213213
}
214+
215+
/**
216+
* Returns the internal of name of the super class (see {@link Type#getInternalName()}). For
217+
* interfaces, the super class is {@link Object}.
218+
*
219+
* @return the internal name of the super class, or {@literal null} for {@link Object} class.
220+
* @see ClassVisitor#visit(int, int, String, String, String, String[])
221+
*/
222+
String getSuperName() {
223+
// super_class is after the access_flags and this_class fields (2 bytes each).
224+
return readClass(header + 4, new char[maxStringLength]);
225+
}
226+
227+
/**
228+
* Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}).
229+
*
230+
* @return the internal names of the directly implemented interfaces. Inherited implemented
231+
* interfaces are not returned.
232+
* @see ClassVisitor#visit(int, int, String, String, String, String[])
233+
*/
234+
String[] getInterfaces() {
235+
// interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each).
236+
int currentOffset = header + 6;
237+
int interfacesCount = readUnsignedShort(currentOffset);
238+
String[] interfaces = new String[interfacesCount];
239+
if (interfacesCount > 0) {
240+
char[] charBuffer = new char[maxStringLength];
241+
for (int i = 0; i < interfacesCount; ++i) {
242+
currentOffset += 2;
243+
interfaces[i] = readClass(currentOffset, charBuffer);
244+
}
245+
}
246+
return interfaces;
247+
}
214248

215249
// -----------------------------------------------------------------------------------------------
216250
// Public methods
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
/**
2+
* Copyright 2013-2021 Valery Silaev (http://vsilaev.com)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.commons.javaflow.spi;
17+
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.util.Arrays;
21+
import java.util.Collection;
22+
import java.util.HashSet;
23+
import java.util.Set;
24+
import java.util.regex.Pattern;
25+
26+
public final class ClassMatchStrategies {
27+
private ClassMatchStrategies() {}
28+
29+
public static final ClassMatchStrategy MATCH_NONE = new ClassMatchStrategy() {
30+
@Override
31+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
32+
return false;
33+
}
34+
35+
@Override
36+
public ClassMatcher bind(ResourceLoader ignore) {
37+
return ClassMatcher.MATCH_NONE;
38+
}
39+
};
40+
41+
public static final ClassMatchStrategy MATCH_ALL = new ClassMatchStrategy() {
42+
@Override
43+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
44+
return true;
45+
}
46+
47+
@Override
48+
public ClassMatcher bind(ResourceLoader ignore) {
49+
return ClassMatcher.MATCH_ALL;
50+
}
51+
};
52+
53+
public static ClassMatchStrategy whenAll(ClassMatchStrategy... matchers) {
54+
return whenAll(Arrays.asList(matchers));
55+
}
56+
57+
public static ClassMatchStrategy whenAll(final Collection<? extends ClassMatchStrategy> matchers) {
58+
return new ClassMatchStrategy() {
59+
@Override
60+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
61+
for (ClassMatchStrategy m : matchers) {
62+
if (!m.matches(name, signature, superName, interfaces, loader)) {
63+
return false;
64+
}
65+
}
66+
return true;
67+
}
68+
};
69+
}
70+
71+
public static ClassMatchStrategy whenAny(ClassMatchStrategy... matchers) {
72+
return whenAny(Arrays.asList(matchers));
73+
}
74+
75+
public static ClassMatchStrategy whenAny(final Collection<? extends ClassMatchStrategy> matchers) {
76+
return new ClassMatchStrategy() {
77+
@Override
78+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
79+
for (ClassMatchStrategy m : matchers) {
80+
if (m.matches(name, signature, superName, interfaces, loader)) {
81+
return true;
82+
}
83+
}
84+
return false;
85+
}
86+
};
87+
}
88+
89+
public static ClassMatchStrategy negate(final ClassMatchStrategy matcher) {
90+
return new ClassMatchStrategy() {
91+
@Override
92+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
93+
return !matcher.matches(name, signature, superName, interfaces, loader);
94+
}
95+
};
96+
}
97+
98+
public static ClassMatchStrategy byClassName(String className, final boolean namePart) {
99+
final String cn = className(className);
100+
return new ClassMatchStrategy() {
101+
@Override
102+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
103+
return namePart && name.contains(cn) || name.equals(cn);
104+
}
105+
};
106+
}
107+
108+
public static ClassMatchStrategy byClassNamePattern(final String classNamePattern) {
109+
final Pattern pattern = Pattern.compile("^" + classNamePattern + "$");
110+
return new ClassMatchStrategy() {
111+
@Override
112+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
113+
return pattern.matcher(name).matches();
114+
}
115+
};
116+
}
117+
118+
public static ClassMatchStrategy bySuperClass(final ClassMatchStrategy nested) {
119+
return new ClassMatchStrategy() {
120+
@Override
121+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
122+
String cname = superName;
123+
while (null != cname && cname.length() > 0) {
124+
ClassHeaderReader chr;
125+
try {
126+
chr = getClassHeader(loader, cname);
127+
} catch (IOException ex) {
128+
throw new RuntimeException(ex);
129+
}
130+
String nextSuperName = chr.getSuperName();
131+
if (nested.matches(cname, null, nextSuperName, chr.getInterfaces(), loader)) {
132+
return true;
133+
}
134+
cname = nextSuperName;
135+
}
136+
return false;
137+
}
138+
};
139+
}
140+
141+
public static ClassMatchStrategy byInterface(final ClassMatchStrategy nested) {
142+
return new ClassMatchStrategy() {
143+
@Override
144+
public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader) {
145+
if (null == interfaces || interfaces.length == 0) {
146+
return false;
147+
}
148+
Set<String> visited = new HashSet<String>();
149+
for (String intf : interfaces) {
150+
if (matchInterface(intf, nested, visited, loader)) {
151+
return true;
152+
}
153+
}
154+
return false;
155+
}
156+
};
157+
}
158+
159+
private static boolean matchInterface(String intf, ClassMatchStrategy nested, Set<String> visited, ResourceLoader loader) {
160+
if (visited.contains(intf)) {
161+
return false;
162+
}
163+
ClassHeaderReader chr;
164+
try {
165+
chr = getClassHeader(loader, intf);
166+
} catch (IOException ex) {
167+
throw new RuntimeException(ex);
168+
}
169+
if (nested.matches(intf, null, chr.getSuperName(), chr.getInterfaces(), loader)) {
170+
return true;
171+
}
172+
visited.add(intf);
173+
String[] nextInterfaces = chr.getInterfaces();
174+
for (String nextInterface : nextInterfaces) {
175+
if (matchInterface(nextInterface, nested, visited, loader)) {
176+
return true;
177+
}
178+
}
179+
return false;
180+
}
181+
182+
private static String className(String internalClassName) {
183+
return internalClassName != null ? internalClassName.replace('.', '/') : null;
184+
}
185+
186+
private static ClassHeaderReader getClassHeader(ResourceLoader loader, String className) throws IOException {
187+
return new ClassHeaderReader(getClassBytes(loader, className));
188+
}
189+
190+
private static byte[] getClassBytes(ResourceLoader loader, String className) throws IOException, SecurityException {
191+
InputStream in = loader.getResourceAsStream(className + ".class");
192+
try {
193+
return getStreamBytes(in);
194+
} finally {
195+
if (null != in) {
196+
try {
197+
in.close();
198+
} catch (IOException ignore) {
199+
}
200+
}
201+
}
202+
}
203+
204+
private static byte[] getStreamBytes(InputStream stream) throws IOException {
205+
int BUFFER_SIZE = 4096;
206+
FastByteArrayOutputStream baos = new FastByteArrayOutputStream(BUFFER_SIZE);
207+
try {
208+
209+
int bytesRead;
210+
byte[] buffer = new byte[BUFFER_SIZE];
211+
212+
while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) > 0) {
213+
baos.write(buffer, 0, bytesRead);
214+
}
215+
216+
byte[] data = baos.unsafeBytes();
217+
return data;
218+
219+
} finally {
220+
baos.close();
221+
}
222+
}
223+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright 2013-2021 Valery Silaev (http://vsilaev.com)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.commons.javaflow.spi;
17+
18+
public abstract class ClassMatchStrategy {
19+
abstract public boolean matches(String name, String signature, String superName, String[] interfaces, ResourceLoader loader);
20+
21+
public ClassMatcher bind(final ResourceLoader loader) {
22+
return new ClassMatcher() {
23+
@Override
24+
public boolean matches(String name, String signature, String superName, String[] interfaces) {
25+
return ClassMatchStrategy.this.matches(name, signature, superName, interfaces, loader);
26+
}
27+
};
28+
}
29+
}

0 commit comments

Comments
 (0)