Skip to content

Commit b3e8489

Browse files
christophstroblodrotbohm
authored andcommitted
Added AOT metadata.
We now register @BasePathAwareController instances for class proxy generation. Also, we scan the packages of repository definitions for projection interfaces to register reflective access for them. Fixes #2183.
1 parent f48ab5a commit b3e8489

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
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+
* https://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.springframework.data.rest.webmvc.aot;
17+
18+
import org.springframework.data.rest.webmvc.BasePathAwareController;
19+
import org.springframework.hateoas.aot.ControllerMethodReturnTypeAotProcessor;
20+
21+
/**
22+
* Extension of {@link ControllerMethodReturnTypeAotProcessor} to also pick up controllers defined using
23+
* {@link BasePathAwareController}.
24+
*
25+
* @author Christoph Strobl
26+
* @author Oliver Drotbohm
27+
* @since 4.0
28+
*/
29+
class BasePathAwareControllerAotProcessor extends ControllerMethodReturnTypeAotProcessor {
30+
31+
protected BasePathAwareControllerAotProcessor() {
32+
super(BasePathAwareController.class);
33+
}
34+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
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+
* https://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.springframework.data.rest.webmvc.aot;
17+
18+
import java.util.HashSet;
19+
import java.util.Set;
20+
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
import org.springframework.aop.SpringProxy;
24+
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
25+
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
26+
import org.springframework.beans.factory.support.RegisteredBean;
27+
import org.springframework.core.DecoratingProxy;
28+
import org.springframework.core.io.DefaultResourceLoader;
29+
import org.springframework.data.projection.TargetAware;
30+
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
31+
import org.springframework.data.rest.core.config.Projection;
32+
import org.springframework.data.util.AnnotatedTypeScanner;
33+
import org.springframework.util.ClassUtils;
34+
import org.springframework.util.ObjectUtils;
35+
36+
/**
37+
* {@link BeanRegistrationAotProcessor} to register proxy hints for projection interfaces.
38+
*
39+
* @author Oliver Drotbohm
40+
* @since 4.0
41+
*/
42+
class ProjectionProxyAotProcessor implements BeanRegistrationAotProcessor {
43+
44+
private static final Logger LOGGER = LoggerFactory.getLogger(ProjectionProxyAotProcessor.class);
45+
46+
private static Class<?>[] ADDITIONAL_INTERFACES = new Class<?>[] { //
47+
TargetAware.class, //
48+
SpringProxy.class, //
49+
DecoratingProxy.class
50+
};
51+
52+
private Set<String> packagesSeen = new HashSet<>();
53+
54+
@Override
55+
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
56+
57+
if (!ClassUtils.isAssignable(RepositoryFactoryBeanSupport.class, registeredBean.getBeanClass())) {
58+
return null;
59+
}
60+
61+
var holder = registeredBean.getMergedBeanDefinition() //
62+
.getConstructorArgumentValues() //
63+
.getIndexedArgumentValue(0, String.class);
64+
65+
var repositoryInterface = (String) holder.getValue();
66+
var packageToScan = ClassUtils.getPackageName(repositoryInterface);
67+
68+
LOGGER.debug("Detecting projection interfaces in {}", packageToScan);
69+
70+
if (packagesSeen.contains(packageToScan)) {
71+
return null;
72+
}
73+
74+
packagesSeen.add(packageToScan);
75+
76+
return (context, code) -> {
77+
78+
var classLoader = registeredBean.getBeanFactory().getBeanClassLoader();
79+
var proxies = context.getRuntimeHints().proxies();
80+
81+
var scanner = new AnnotatedTypeScanner(Projection.class);
82+
scanner.setResourceLoader(new DefaultResourceLoader(classLoader));
83+
scanner.findTypes(packageToScan)
84+
.forEach(it -> {
85+
86+
LOGGER.debug("Registering proxy config for projection interface {}.", it.getName());
87+
88+
proxies.registerJdkProxy(ObjectUtils.addObjectToArray(ADDITIONAL_INTERFACES, it, 0));
89+
});
90+
91+
};
92+
}
93+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/** AOT & native configuration for rest.webmvc */
2+
package org.springframework.data.rest.webmvc.aot;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
2+
org.springframework.data.rest.webmvc.aot.BasePathAwareControllerAotProcessor,\
3+
org.springframework.data.rest.webmvc.aot.ProjectionProxyAotProcessor

0 commit comments

Comments
 (0)