Skip to content

Commit 49af7e0

Browse files
committed
Extract classpath scanning into separate class
1 parent 312bcdf commit 49af7e0

File tree

2 files changed

+215
-144
lines changed

2 files changed

+215
-144
lines changed
Lines changed: 10 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,19 @@
11
package grails.boot.config
2-
import grails.config.Settings
2+
3+
import grails.boot.config.tools.ClassPathScanner
34
import grails.core.GrailsApplicationClass
4-
import grails.io.IOUtils
55
import groovy.transform.CompileStatic
6-
import groovy.transform.InheritConstructors
7-
import groovy.transform.Memoized
86
import groovy.util.logging.Slf4j
9-
import org.grails.asm.AnnotationMetadataReader
107
import org.grails.compiler.injection.AbstractGrailsArtefactTransformer
118
import org.grails.spring.aop.autoproxy.GroovyAwareAspectJAwareAdvisorAutoProxyCreator
129
import org.springframework.aop.config.AopConfigUtils
1310
import org.springframework.context.ApplicationContext
1411
import org.springframework.context.ApplicationContextAware
15-
import org.springframework.context.ResourceLoaderAware
1612
import org.springframework.context.annotation.Bean
17-
import org.springframework.core.io.DefaultResourceLoader
18-
import org.springframework.core.io.Resource
19-
import org.springframework.core.io.UrlResource
2013
import org.springframework.core.io.support.PathMatchingResourcePatternResolver
21-
import org.springframework.core.io.support.ResourcePatternResolver
22-
import org.springframework.core.type.classreading.CachingMetadataReaderFactory
23-
import org.springframework.util.ClassUtils
2414

2515
import java.lang.reflect.Field
16+
2617
/**
2718
* A base class for configurations that bootstrap a Grails application
2819
*
@@ -35,7 +26,6 @@ import java.lang.reflect.Field
3526
class GrailsAutoConfiguration implements GrailsApplicationClass, ApplicationContextAware {
3627

3728
private static final String APC_PRIORITY_LIST_FIELD = "APC_PRIORITY_LIST";
38-
private static final List DEFAULT_IGNORED_ROOT_PACKAGES = ['com', 'org', 'net', 'co', 'java', 'javax', 'groovy']
3929

4030
static {
4131
try {
@@ -52,8 +42,6 @@ class GrailsAutoConfiguration implements GrailsApplicationClass, ApplicationCont
5242
}
5343
}
5444

55-
ResourcePatternResolver resourcePatternResolver = new GrailsClasspathIgnoringResourceResolver(getClass())
56-
5745
ApplicationContext applicationContext
5846

5947
/**
@@ -68,34 +56,17 @@ class GrailsAutoConfiguration implements GrailsApplicationClass, ApplicationCont
6856
* @return The classes that constitute the Grails application
6957
*/
7058
Collection<Class> classes() {
71-
def readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver)
72-
def packages = packageNames().unique()
7359
Collection<Class> classes = new HashSet()
74-
for (pkg in packages) {
75-
if(pkg == null) continue
76-
if(ignoredRootPackages().contains(pkg)) {
77-
continue
78-
}
79-
// if it is the default package
80-
if(pkg == "") {
81-
// try the default package in case of a script without recursing into subpackages
82-
log.error("The application defines a Groovy source using the default package. Please move all Groovy sources into a package.")
83-
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "*.class"
84-
classes.addAll scanUsingPattern(pattern, readerFactory)
85-
}
86-
else {
87-
88-
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
89-
ClassUtils.convertClassNameToResourcePath(pkg) + Settings.CLASS_RESOURCE_PATTERN;
90-
91-
92-
classes.addAll scanUsingPattern(pattern, readerFactory)
93-
}
9460

61+
ClassPathScanner scanner = new ClassPathScanner()
62+
if(limitScanningToApplication()) {
63+
classes.addAll scanner.scan(getClass(), packageNames())
64+
}
65+
else {
66+
classes.addAll scanner.scan(new PathMatchingResourcePatternResolver(applicationContext), packageNames())
9567
}
9668

97-
98-
def classLoader = Thread.currentThread().contextClassLoader
69+
ClassLoader classLoader = getClass().getClassLoader()
9970
for(cls in AbstractGrailsArtefactTransformer.transformedClassNames) {
10071
try {
10172
classes << classLoader.loadClass(cls)
@@ -107,12 +78,6 @@ class GrailsAutoConfiguration implements GrailsApplicationClass, ApplicationCont
10778
return classes
10879
}
10980

110-
/**
111-
* @return The root packages to ignore by default
112-
*/
113-
protected List ignoredRootPackages() {
114-
DEFAULT_IGNORED_ROOT_PACKAGES
115-
}
11681

11782
/**
11883
* Whether classpath scanning should be limited to the application and not dependent JAR files. Users can override this method to enable more broad scanning
@@ -140,23 +105,6 @@ class GrailsAutoConfiguration implements GrailsApplicationClass, ApplicationCont
140105
}
141106

142107

143-
private Collection<Class> scanUsingPattern(String pattern, CachingMetadataReaderFactory readerFactory) {
144-
def resources = limitScanningToApplication() ? this.resourcePatternResolver.getResources(pattern) : new PathMatchingResourcePatternResolver(applicationContext).getResources(pattern)
145-
def classLoader = Thread.currentThread().contextClassLoader
146-
Collection<Class> classes = []
147-
for (Resource res in resources) {
148-
// ignore closures / inner classes
149-
if(!res.filename.contains('$') && !res.filename.startsWith("gsp_")) {
150-
def reader = new AnnotationMetadataReader(res, classLoader)
151-
def metadata = reader.annotationMetadata
152-
if (metadata.annotationTypes.any() { String annotation -> annotation.startsWith('grails.') }) {
153-
classes << classLoader.loadClass(reader.classMetadata.className)
154-
}
155-
}
156-
}
157-
return classes
158-
}
159-
160108
@Override
161109
Closure doWithSpring() { null }
162110

@@ -185,87 +133,5 @@ class GrailsAutoConfiguration implements GrailsApplicationClass, ApplicationCont
185133
// no-op
186134
}
187135

188-
@CompileStatic
189-
@InheritConstructors
190-
@Slf4j
191-
private static class GrailsClasspathIgnoringResourceResolver extends PathMatchingResourcePatternResolver {
192-
193-
GrailsClasspathIgnoringResourceResolver(Class applicationClass) {
194-
super(new DefaultResourceLoader(new ApplicationRelativeClassLoader(applicationClass)))
195-
}
196-
197-
@Memoized(maxCacheSize = 20)
198-
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
199-
Set<Resource> result = new LinkedHashSet<Resource>(16)
200-
ClassLoader cl = getClassLoader()
201-
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path))
202-
while (resourceUrls.hasMoreElements()) {
203-
204-
URL url = resourceUrls.nextElement()
205-
// if the path is from a JAR file ignore, plugins inside JAR files will have their own mechanism for loading
206-
if(!url.path.contains('jar!/grails/')) {
207-
result.add(convertClassLoaderURL(url))
208-
}
209-
210-
}
211-
return result
212-
}
213-
214-
@Memoized
215-
protected Resource[] findAllClassPathResources(String location) throws IOException {
216-
return super.findAllClassPathResources(location)
217-
}
218-
219-
@Memoized
220-
protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
221-
return super.findPathMatchingResources(locationPattern)
222-
}
223-
224-
}
225-
226-
private static class ApplicationRelativeClassLoader extends URLClassLoader {
227-
228-
final URL rootResource
229-
final Class applicationClass
230-
final boolean jarDeployed
231-
232-
ApplicationRelativeClassLoader(Class applicationClass) {
233-
super([ IOUtils.findRootResource(applicationClass)] as URL[])
234-
235-
this.rootResource = getURLs()[0]
236-
this.applicationClass = applicationClass
237-
String urlStr = rootResource.toString()
238-
jarDeployed = urlStr.startsWith("jar:")
239-
try {
240-
URL withoutBang = new URL("${urlStr.substring(0, urlStr.length() - 2)}/")
241-
addURL(withoutBang)
242-
243-
} catch (MalformedURLException e) {
244-
// ignore, running as a WAR
245-
}
246-
}
247-
248-
@Override
249-
Enumeration<URL> getResources(String name) throws IOException {
250-
if(jarDeployed && name == '') {
251-
return applicationClass.getClassLoader().getResources(name)
252-
}
253-
else {
254-
return super.findResources(name)
255-
}
256-
}
257-
258-
@Override
259-
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
260-
try {
261-
return super.loadClass(name, resolve)
262-
} catch (ClassNotFoundException cnfe) {
263-
return applicationClass.getClassLoader().loadClass(name)
264-
}
265-
}
266-
}
267-
268-
269-
270136
}
271137

0 commit comments

Comments
 (0)