Browse Source
This commit updates ApplicationContextAotGenerator to register a handler that process Cglib generated classes. The handler registers such classes to the GeneratedFiles and provide a hint so that it can be instantiated using reflection. Closes gh-28954pull/28964/head
Stephane Nicoll
2 years ago
7 changed files with 237 additions and 22 deletions
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.context.aot; |
||||
|
||||
import java.util.function.BiConsumer; |
||||
import java.util.function.Consumer; |
||||
|
||||
import org.springframework.aot.generate.GeneratedFiles; |
||||
import org.springframework.aot.generate.GeneratedFiles.Kind; |
||||
import org.springframework.aot.generate.GenerationContext; |
||||
import org.springframework.aot.hint.MemberCategory; |
||||
import org.springframework.aot.hint.RuntimeHints; |
||||
import org.springframework.aot.hint.TypeHint.Builder; |
||||
import org.springframework.aot.hint.TypeReference; |
||||
import org.springframework.cglib.core.ReflectUtils; |
||||
import org.springframework.core.io.ByteArrayResource; |
||||
|
||||
/** |
||||
* Handle generated classes by adding them to a {@link GenerationContext}, |
||||
* and register the necessary hints so that they can be instantiated. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @see ReflectUtils#setGeneratedClassHandler(BiConsumer) |
||||
*/ |
||||
class GeneratedClassHandler implements BiConsumer<String, byte[]> { |
||||
|
||||
private static final Consumer<Builder> asCglibProxy = hint -> |
||||
hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); |
||||
|
||||
private final RuntimeHints runtimeHints; |
||||
|
||||
private final GeneratedFiles generatedFiles; |
||||
|
||||
GeneratedClassHandler(GenerationContext generationContext) { |
||||
this.runtimeHints = generationContext.getRuntimeHints(); |
||||
this.generatedFiles = generationContext.getGeneratedFiles(); |
||||
} |
||||
|
||||
@Override |
||||
public void accept(String className, byte[] content) { |
||||
this.runtimeHints.reflection().registerType(TypeReference.of(className), asCglibProxy); |
||||
String path = className.replace(".", "/") + ".class"; |
||||
this.generatedFiles.addFile(Kind.CLASS, path, new ByteArrayResource(content)); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.context.aot; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.aot.generate.GeneratedFiles.Kind; |
||||
import org.springframework.aot.generate.InMemoryGeneratedFiles; |
||||
import org.springframework.aot.hint.MemberCategory; |
||||
import org.springframework.aot.hint.TypeReference; |
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; |
||||
import org.springframework.core.io.InputStreamSource; |
||||
import org.springframework.core.testfixture.aot.generate.TestGenerationContext; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link GeneratedClassHandler}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class GeneratedClassHandlerTests { |
||||
|
||||
private static final byte[] TEST_CONTENT = new byte[] { 'a' }; |
||||
|
||||
private final TestGenerationContext generationContext; |
||||
|
||||
private final GeneratedClassHandler handler; |
||||
|
||||
public GeneratedClassHandlerTests() { |
||||
this.generationContext = new TestGenerationContext(); |
||||
this.handler = new GeneratedClassHandler(this.generationContext); |
||||
} |
||||
|
||||
@Test |
||||
void handlerGenerateRuntimeHints() { |
||||
String className = "com.example.Test$$Proxy$$1"; |
||||
this.handler.accept(className, TEST_CONTENT); |
||||
assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of(className)) |
||||
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)) |
||||
.accepts(this.generationContext.getRuntimeHints()); |
||||
} |
||||
|
||||
@Test |
||||
void handlerRegisterGeneratedClass() throws IOException { |
||||
String className = "com.example.Test$$Proxy$$1"; |
||||
this.handler.accept(className, TEST_CONTENT); |
||||
InMemoryGeneratedFiles generatedFiles = this.generationContext.getGeneratedFiles(); |
||||
assertThat(generatedFiles.getGeneratedFiles(Kind.SOURCE)).isEmpty(); |
||||
assertThat(generatedFiles.getGeneratedFiles(Kind.RESOURCE)).isEmpty(); |
||||
String expectedPath = "com/example/Test$$Proxy$$1.class"; |
||||
assertThat(generatedFiles.getGeneratedFiles(Kind.CLASS)).containsOnlyKeys(expectedPath); |
||||
assertContent(generatedFiles.getGeneratedFiles(Kind.CLASS).get(expectedPath), TEST_CONTENT); |
||||
} |
||||
|
||||
private void assertContent(InputStreamSource source, byte[] expectedContent) throws IOException { |
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); |
||||
source.getInputStream().transferTo(out); |
||||
assertThat(out.toByteArray()).isEqualTo(expectedContent); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.context.testfixture.context.generator.annotation; |
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
@Configuration |
||||
public class CglibConfiguration { |
||||
|
||||
private static final AtomicInteger counter = new AtomicInteger(); |
||||
|
||||
@Bean |
||||
public String prefix() { |
||||
return "Hello" + counter.getAndIncrement(); |
||||
} |
||||
|
||||
@Bean |
||||
public String text() { |
||||
return prefix() + " World"; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue