From f547b6ad2a7ff8a61cb4682a2442aa83d8283af7 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 25 Sep 2023 19:59:39 +0200 Subject: [PATCH 1/3] Polishing --- .../cglib/core/SpringNamingPolicy.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java b/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java index 7eb96dd701..ee595070be 100644 --- a/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java +++ b/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,8 @@ public final class SpringNamingPolicy implements NamingPolicy { public static final SpringNamingPolicy INSTANCE = new SpringNamingPolicy(); - private static final String LABEL = "$$SpringCGLIB$$"; + private static final String SPRING_LABEL = "$$SpringCGLIB$$"; + private SpringNamingPolicy() { } @@ -46,12 +47,12 @@ public final class SpringNamingPolicy implements NamingPolicy { } String base; - int existingLabel = prefix.indexOf(LABEL); + int existingLabel = prefix.indexOf(SPRING_LABEL); if (existingLabel >= 0) { - base = prefix.substring(0, existingLabel + LABEL.length()); + base = prefix.substring(0, existingLabel + SPRING_LABEL.length()); } else { - base = prefix + LABEL; + base = prefix + SPRING_LABEL; } int index = 0; From d17c75a7efe0399b2fdf12873171f963b7ec50da Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 25 Sep 2023 17:44:42 +0200 Subject: [PATCH 2/3] Test status quo for SpringNamingPolicy See gh-31272 --- .../cglib/core/SpringNamingPolicyTests.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java diff --git a/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java b/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java new file mode 100644 index 0000000000..75fd0a89c4 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cglib.core; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringNamingPolicy}. + * + * @author Sam Brannen + * @since 6.0.13 + */ +class SpringNamingPolicyTests { + + private final Set reservedClassNames = new HashSet<>(); + + + @Test + void nullPrefix() { + assertThat(getClassName(null)).isEqualTo("org.springframework.cglib.empty.Object$$SpringCGLIB$$0"); + assertThat(getClassName(null)).isEqualTo("org.springframework.cglib.empty.Object$$SpringCGLIB$$1"); + } + + @Test + void javaPrefix() { + assertThat(getClassName("java.util.ArrayList")).isEqualTo("_java.util.ArrayList$$SpringCGLIB$$0"); + assertThat(getClassName("java.util.ArrayList")).isEqualTo("_java.util.ArrayList$$SpringCGLIB$$1"); + } + + @Test + void javaxPrefix() { + assertThat(getClassName("javax.sql.RowSet")).isEqualTo("_javax.sql.RowSet$$SpringCGLIB$$0"); + assertThat(getClassName("javax.sql.RowSet")).isEqualTo("_javax.sql.RowSet$$SpringCGLIB$$1"); + } + + @Test + void examplePrefix() { + assertThat(getClassName("example.MyComponent")).isEqualTo("example.MyComponent$$SpringCGLIB$$0"); + assertThat(getClassName("example.MyComponent")).isEqualTo("example.MyComponent$$SpringCGLIB$$1"); + } + + @Test + void prefixContainingSpringLabel() { + String generated1 = "example.MyComponent$$SpringCGLIB$$0"; + String generated2 = "example.MyComponent$$SpringCGLIB$$1"; + + assertThat(getClassName(generated1)).isEqualTo(generated1); + assertThat(getClassName(generated1)).isEqualTo(generated2); + } + + private String getClassName(String prefix) { + return getClassName(prefix, null, null); + } + + private String getClassName(String prefix, String source, Object key) { + String className = SpringNamingPolicy.INSTANCE.getClassName(prefix, source, key, reservedClassNames::contains); + reservedClassNames.add(className); + return className; + } + +} From 18456dec52f7c37e86c00804a2c8a7712fc6dde0 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 25 Sep 2023 20:01:33 +0200 Subject: [PATCH 3/3] =?UTF-8?q?Reintroduce=20FastClass=20in=20CGLIB=20clas?= =?UTF-8?q?s=20names=20for=20@=E2=81=A0Configuration=20classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given a @⁠Configuration class named org.example.AppConfig which contains @⁠Bean methods, in Spring Framework 5.3.x and previous versions, the following classes were created when generating the CGLIB proxy. org.example.AppConfig$$EnhancerBySpringCGLIB$$fd7e9baa org.example.AppConfig$$FastClassBySpringCGLIB$$3fec86e org.example.AppConfig$$EnhancerBySpringCGLIB$$fd7e9baa$$FastClassBySpringCGLIB$$82534900 Those class names indicate that 1 class was generated for the proxy for the @⁠Configuration class itself and that 2 additional FastClass classes were generated to support proxying of @⁠Bean methods in superclasses. However, since Spring Framework 6.0, the following classes are created when generating the CGLIB proxy. org.example.AppConfig$$SpringCGLIB$$0 org.example.AppConfig$$SpringCGLIB$$1 org.example.AppConfig$$SpringCGLIB$$2 The above class names make it appear that 3 proxy classes are generated for each @⁠Configuration class, which is misleading. To address that and to align more closely with how such generated classes were named in previous versions of the framework, this commit modifies SpringNamingPolicy so that generated class names once again include "FastClass" when the generated class is for a CGLIB FastClass as opposed to the actual proxy for the @⁠Configuration class. Consequently, with this commit the following classes are created when generating the CGLIB proxy. org.example.AppConfig$$SpringCGLIB$$0 org.example.AppConfig$$SpringCGLIB$$FastClass$$0 org.example.AppConfig$$SpringCGLIB$$FastClass$$1 Closes gh-31272 --- .../aot/ApplicationContextAotGeneratorTests.java | 4 ++-- .../cglib/core/SpringNamingPolicy.java | 10 ++++++++++ .../cglib/core/SpringNamingPolicyTests.java | 11 +++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotGeneratorTests.java b/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotGeneratorTests.java index 77de1ab138..3e98304158 100644 --- a/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotGeneratorTests.java +++ b/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotGeneratorTests.java @@ -359,8 +359,8 @@ class ApplicationContextAotGeneratorTests { applicationContext.registerBean(CglibConfiguration.class); TestGenerationContext context = processAheadOfTime(applicationContext); isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$0"); - isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$1"); - isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$2"); + isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$FastClass$$0"); + isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$FastClass$$1"); } private void isRegisteredCglibClass(TestGenerationContext context, String cglibClassName) throws IOException { diff --git a/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java b/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java index ee595070be..347975a0e0 100644 --- a/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java +++ b/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java @@ -25,6 +25,7 @@ package org.springframework.cglib.core; * in the classpath. * * @author Juergen Hoeller + * @author Sam Brannen * @since 3.2.8 / 6.0 */ public final class SpringNamingPolicy implements NamingPolicy { @@ -33,6 +34,8 @@ public final class SpringNamingPolicy implements NamingPolicy { private static final String SPRING_LABEL = "$$SpringCGLIB$$"; + private static final String FAST_CLASS_SUFFIX = "FastClass$$"; + private SpringNamingPolicy() { } @@ -55,6 +58,13 @@ public final class SpringNamingPolicy implements NamingPolicy { base = prefix + SPRING_LABEL; } + // When the generated class name is for a FastClass, the source is + // "org.springframework.cglib.reflect.FastClass". + boolean isFastClass = (source != null && source.endsWith(".FastClass")); + if (isFastClass && !prefix.contains(FAST_CLASS_SUFFIX)) { + base += FAST_CLASS_SUFFIX; + } + int index = 0; String attempt = base + index; while (names.evaluate(attempt)) { diff --git a/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java b/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java index 75fd0a89c4..6f3e32e58d 100644 --- a/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java +++ b/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java @@ -21,6 +21,8 @@ import java.util.Set; import org.junit.jupiter.api.Test; +import org.springframework.cglib.reflect.FastClass; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -67,6 +69,15 @@ class SpringNamingPolicyTests { assertThat(getClassName(generated1)).isEqualTo(generated2); } + @Test + void fastClass() { + String prefix = "example.MyComponent"; + String source = FastClass.class.getName(); + assertThat(getClassName(prefix, "a.b.c", null)).isEqualTo("example.MyComponent$$SpringCGLIB$$0"); + assertThat(getClassName(prefix, source, null)).isEqualTo("example.MyComponent$$SpringCGLIB$$FastClass$$0"); + assertThat(getClassName(prefix, source, null)).isEqualTo("example.MyComponent$$SpringCGLIB$$FastClass$$1"); + } + private String getClassName(String prefix) { return getClassName(prefix, null, null); }