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 81767e3cfe..d02d504ee8 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 @@ -363,8 +363,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 7eb96dd701..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 @@ -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. @@ -25,13 +25,17 @@ 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 { public static final SpringNamingPolicy INSTANCE = new SpringNamingPolicy(); - private static final String LABEL = "$$SpringCGLIB$$"; + private static final String SPRING_LABEL = "$$SpringCGLIB$$"; + + private static final String FAST_CLASS_SUFFIX = "FastClass$$"; + private SpringNamingPolicy() { } @@ -46,12 +50,19 @@ 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; + } + + // 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; 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..6f3e32e58d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/cglib/core/SpringNamingPolicyTests.java @@ -0,0 +1,91 @@ +/* + * 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 org.springframework.cglib.reflect.FastClass; + +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); + } + + @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); + } + + private String getClassName(String prefix, String source, Object key) { + String className = SpringNamingPolicy.INSTANCE.getClassName(prefix, source, key, reservedClassNames::contains); + reservedClassNames.add(className); + return className; + } + +}