Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 51f1415

Browse files
committed
Replace cglib with ByteBuddy
1 parent 7870685 commit 51f1415

File tree

7 files changed

+163
-51
lines changed

7 files changed

+163
-51
lines changed

CHANGES

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
Platform 3.27
22

3-
* Java 11
3+
* Java versions
44

5-
We increased the minimum Java version to 17.
5+
* We increased the minimum Java version to 17.
6+
7+
* We now support Java 21.
8+
9+
* Configuration
10+
11+
- In order to support newer versions of Java,
12+
ConfigAssertions now uses ByteBuddy instead of cglib.
13+
INCOMPATIBLE CHANGE: ConfigAssertions.assertRecordedDefaults()
14+
can no longer test config classes that are package private or have
15+
package private configuration attributes. The configuration classes
16+
and their configuration getters and setters must be made public.
617

718
* Maven plugin upgrades
819
- JaCoCo to 0.8.12 (was 0.8.8)

configuration/pom.xml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@
5353
</dependency>
5454

5555
<dependency>
56-
<groupId>cglib</groupId>
57-
<artifactId>cglib-nodep</artifactId>
58-
<version>3.2.8</version>
56+
<groupId>net.bytebuddy</groupId>
57+
<artifactId>byte-buddy</artifactId>
5958
</dependency>
6059

6160
<dependency>

configuration/src/main/java/com/proofpoint/configuration/testing/ConfigAssertions.java

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
*/
1616
package com.proofpoint.configuration.testing;
1717

18-
import com.google.common.collect.MapMaker;
18+
import com.google.common.collect.ImmutableSet;
1919
import com.proofpoint.configuration.ConfigurationFactory;
2020
import com.proofpoint.configuration.ConfigurationMetadata;
2121
import com.proofpoint.configuration.ConfigurationMetadata.AttributeMetadata;
2222
import com.proofpoint.configuration.MapClasses;
23-
import net.sf.cglib.proxy.Enhancer;
24-
import net.sf.cglib.proxy.MethodInterceptor;
25-
import net.sf.cglib.proxy.MethodProxy;
23+
import net.bytebuddy.ByteBuddy;
24+
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
25+
import net.bytebuddy.implementation.InvocationHandlerAdapter;
26+
import net.bytebuddy.matcher.ElementMatchers;
2627

2728
import java.lang.reflect.Method;
2829
import java.util.HashSet;
@@ -31,9 +32,11 @@
3132
import java.util.Set;
3233
import java.util.TreeMap;
3334
import java.util.TreeSet;
34-
import java.util.concurrent.ConcurrentMap;
3535

36+
import static com.google.common.collect.Sets.newConcurrentHashSet;
3637
import static com.proofpoint.configuration.ConfigurationMetadata.isConfigClass;
38+
import static java.lang.reflect.Modifier.PUBLIC;
39+
import static java.lang.reflect.Modifier.isPublic;
3740
import static org.testng.Assert.assertEquals;
3841
import static org.testng.Assert.assertNotEquals;
3942
import static org.testng.Assert.assertNotNull;
@@ -61,7 +64,7 @@ public static <T> void assertFullMapping(Map<String, String> properties, T expec
6164
assertNotNull(properties, "properties");
6265
assertNotNull(expected, "expected");
6366

64-
@SuppressWarnings("unchecked") Class<T> configClass = (Class<T>) expected.getClass();
67+
Class<T> configClass = getClass(expected);
6568
ConfigurationMetadata<T> metadata = ConfigurationMetadata.getValidConfigurationMetadata(configClass);
6669

6770
// verify all supplied properties are supported and not deprecated
@@ -253,9 +256,19 @@ public static <T> void assertRecordedDefaults(T recordedConfig)
253256

254257
T config = recordedConfigData.getInstance();
255258

256-
@SuppressWarnings("unchecked") Class<T> configClass = (Class<T>) config.getClass();
259+
Class<T> configClass = getClass(config);
257260
ConfigurationMetadata<?> metadata = ConfigurationMetadata.getValidConfigurationMetadata(configClass);
258261

262+
// assert class has no package-private config attributes
263+
for (AttributeMetadata attribute : metadata.getAttributes().values()) {
264+
if (!isPublic(attribute.getInjectionPoint().getSetter().getModifiers())) {
265+
fail("Cannot assertRecordedDefaults() on non-public config setter: " + attribute.getInjectionPoint().getSetter().getName());
266+
}
267+
if (!isPublic(attribute.getGetter().getModifiers())) {
268+
fail("Cannot assertRecordedDefaults() on non-public config getter: " + attribute.getGetter().getName());
269+
}
270+
}
271+
259272
// collect information about the attributes that have been set
260273
Map<String, Object> attributeValues = new TreeMap<>();
261274
Set<String> setDeprecatedAttributes = new TreeSet<>();
@@ -285,7 +298,6 @@ public static <T> void assertRecordedDefaults(T recordedConfig)
285298
Set<Method> invalidInvocations = new HashSet<>(invokedMethods);
286299
invalidInvocations.removeAll(validSetterMethods);
287300
fail("Invoked setter without @Config: " + invalidInvocations);
288-
289301
}
290302

291303
// verify all supplied attributes are supported
@@ -332,33 +344,42 @@ public static <T> void assertRecordedDefaults(T recordedConfig)
332344
}
333345

334346
public static <T> T recordDefaults(Class<T> type)
347+
{
348+
Class<? extends T> loaded = new ByteBuddy()
349+
.subclass(type)
350+
.implement($$RecordingConfigProxy.class)
351+
.method(ElementMatchers.any())
352+
.intercept(createInvocationHandler(type))
353+
.make()
354+
.load(type.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
355+
.getLoaded();
356+
try {
357+
return loaded.getConstructor().newInstance();
358+
}
359+
catch (ReflectiveOperationException e) {
360+
throw new AssertionError("Failed to instantiate proxy class for " + type.getName(), e);
361+
}
362+
}
363+
364+
@SuppressWarnings("ObjectEquality")
365+
private static <T> InvocationHandlerAdapter createInvocationHandler(Class<T> type)
335366
{
336367
final T instance = newDefaultInstance(type);
337-
@SuppressWarnings("unchecked") T proxy = (T) Enhancer.create(type, new Class[]{$$RecordingConfigProxy.class}, new MethodInterceptor()
338-
{
339-
private final ConcurrentMap<Method, Object> invokedMethods = new MapMaker().makeMap();
340-
341-
@Override
342-
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
343-
throws Throwable
344-
{
345-
if (GET_RECORDING_CONFIG_METHOD.equals(method)) {
346-
return new $$RecordedConfigData<>(instance, Set.copyOf(invokedMethods.keySet()));
347-
}
368+
Set<Method> invokedMethods = newConcurrentHashSet();
369+
370+
return InvocationHandlerAdapter.of((proxy, method, args) -> {
371+
if (GET_RECORDING_CONFIG_METHOD.equals(method)) {
372+
return new $$RecordedConfigData<>(instance, ImmutableSet.copyOf(invokedMethods));
373+
}
348374

349-
invokedMethods.put(method, Boolean.TRUE);
375+
invokedMethods.add(method);
350376

351-
Object result = methodProxy.invoke(instance, args);
352-
if (result == instance) {
353-
return proxy;
354-
}
355-
else {
356-
return result;
357-
}
377+
Object result = method.invoke(instance, args);
378+
if (result == instance) {
379+
return proxy;
358380
}
381+
return result;
359382
});
360-
361-
return proxy;
362383
}
363384

364385
static <T> $$RecordedConfigData<T> getRecordedConfig(T config)
@@ -399,6 +420,11 @@ public interface $$RecordingConfigProxy<T>
399420
$$RecordedConfigData<T> $$getRecordedConfig();
400421
}
401422

423+
@SuppressWarnings("unchecked")
424+
private static <T> Class<T> getClass(T object)
425+
{
426+
return (Class<T>) object.getClass();
427+
}
402428

403429
private static <T> T newInstance(Class<T> configClass, Map<String, String> properties)
404430
{
@@ -419,10 +445,9 @@ private static <T> Object invoke(T actual, Method getter)
419445
{
420446
try {
421447
return getter.invoke(actual);
422-
} catch (Exception e) {
423-
AssertionError error = new AssertionError(String.format("Exception invoking %s", getter.toGenericString()));
424-
error.initCause(e);
425-
throw error;
448+
}
449+
catch (ReflectiveOperationException e) {
450+
throw new AssertionError("Exception invoking " + getter.toGenericString(), e);
426451
}
427452
}
428453
}

configuration/src/test/java/com/proofpoint/configuration/testing/TestConfigAssertions.java

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,44 @@ public void testDefaultsFailDeprecatedAttribute()
139139
}
140140
}
141141

142+
@Test
143+
public void testRecordedDefaultsFailPrivateGetter()
144+
{
145+
boolean pass = true;
146+
try {
147+
assertRecordedDefaults(recordDefaults(PrivateGetterPersonConfig.class)
148+
.setName("Dain"));
149+
}
150+
catch (AssertionError e) {
151+
// expected
152+
pass = false;
153+
assertContains(e.getMessage(), "Cannot assertRecordedDefaults() on non-public config getter: getName");
154+
}
155+
156+
if (pass) {
157+
fail("Expected AssertionError");
158+
}
159+
}
160+
161+
@Test
162+
public void testRecordedDefaultsFailPrivateSetter()
163+
{
164+
boolean pass = true;
165+
try {
166+
assertRecordedDefaults(recordDefaults(PrivateSetterPersonConfig.class)
167+
.setName("Dain"));
168+
}
169+
catch (AssertionError e) {
170+
// expected
171+
pass = false;
172+
assertContains(e.getMessage(), "Cannot assertRecordedDefaults() on non-public config setter: setName");
173+
}
174+
175+
if (pass) {
176+
fail("Expected AssertionError");
177+
}
178+
}
179+
142180
@Test
143181
public void testExplicitPropertyMappings()
144182
{
@@ -566,64 +604,64 @@ public void testLegacyPropertiesWithMap()
566604
assertLegacyEquivalence(MapConfig.class, currentProperties, oldProperties, olderProperties);
567605
}
568606

569-
static class PersonConfig
607+
public static class PersonConfig
570608
{
571609
private String name = "Dain";
572610
private String email = "dain@proofpoint.com";
573611
private String phone;
574612
private URI homePage = URI.create("http://iq80.com");
575613

576-
String getName()
614+
public String getName()
577615
{
578616
return name;
579617
}
580618

581619
@Config("name")
582-
PersonConfig setName(String name)
620+
public PersonConfig setName(String name)
583621
{
584622
this.name = name;
585623
return this;
586624
}
587625

588-
String getEmail()
626+
public String getEmail()
589627
{
590628
return email;
591629
}
592630

593631
@Config("email")
594632
@LegacyConfig({"exchange-id", "notes-id"})
595-
PersonConfig setEmail(String email)
633+
public PersonConfig setEmail(String email)
596634
{
597635
this.email = email;
598636
return this;
599637
}
600638

601-
String getPhone()
639+
public String getPhone()
602640
{
603641
return phone;
604642
}
605643

606644
@Config("phone")
607-
PersonConfig setPhone(String phone)
645+
public PersonConfig setPhone(String phone)
608646
{
609647
this.phone = phone;
610648
return this;
611649
}
612650

613-
URI getHomePage()
651+
public URI getHomePage()
614652
{
615653
return homePage;
616654
}
617655

618656
@Config("home-page")
619-
PersonConfig setHomePage(URI homePage)
657+
public PersonConfig setHomePage(URI homePage)
620658
{
621659
this.homePage = homePage;
622660
return this;
623661
}
624662

625663
@LegacyConfig(value = "home-page-url", replacedBy = "home-page")
626-
PersonConfig setHomePageUrl(URL homePage)
664+
public PersonConfig setHomePageUrl(URL homePage)
627665
{
628666
try {
629667
this.homePage = homePage.toURI();
@@ -635,6 +673,40 @@ PersonConfig setHomePageUrl(URL homePage)
635673
}
636674
}
637675

676+
public static class PrivateGetterPersonConfig
677+
{
678+
private String name = "Dain";
679+
680+
String getName()
681+
{
682+
return name;
683+
}
684+
685+
@Config("name")
686+
public PrivateGetterPersonConfig setName(String name)
687+
{
688+
this.name = name;
689+
return this;
690+
}
691+
}
692+
693+
public static class PrivateSetterPersonConfig
694+
{
695+
private String name = "Dain";
696+
697+
public String getName()
698+
{
699+
return name;
700+
}
701+
702+
@Config("name")
703+
PrivateSetterPersonConfig setName(String name)
704+
{
705+
this.name = name;
706+
return this;
707+
}
708+
}
709+
638710
static class NoLegacyConfig
639711
{
640712
private String name = "Dain";

jaxrs/pom.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@
191191
<dependency>
192192
<groupId>net.bytebuddy</groupId>
193193
<artifactId>byte-buddy</artifactId>
194-
<version>1.12.9</version>
195194
</dependency>
196195

197196
<dependency>

library/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,12 @@
12751275
<version>3.2</version>
12761276
</dependency>
12771277

1278+
<dependency>
1279+
<groupId>net.bytebuddy</groupId>
1280+
<artifactId>byte-buddy</artifactId>
1281+
<version>1.12.9</version>
1282+
</dependency>
1283+
12781284
<dependency>
12791285
<groupId>io.airlift</groupId>
12801286
<artifactId>slice</artifactId>

sample-server/src/main/java/com/proofpoint/platform/sample/StoreConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ StoreConfig setTtlInMs(int duration)
3636
}
3737

3838
@Config("store.ttl")
39-
StoreConfig setTtl(Duration ttl)
39+
public StoreConfig setTtl(Duration ttl)
4040
{
4141
this.ttl = requireNonNull(ttl, "ttl must not be null");
4242
return this;
4343
}
4444

4545
@MinDuration(value = "1m", message = "must be at least 1m")
46-
Duration getTtl()
46+
public Duration getTtl()
4747
{
4848
return ttl;
4949
}

0 commit comments

Comments
 (0)