Skip to content

Commit 94b47a7

Browse files
improve domain class detection
One problematic scenario is when a domain class is used as a command object, the SourceUnit that is being used to figure out if this is a domain class or not is the source unit of the controller, not the source unit of the domain class so the previous logic wasn’t working. It looks like something changed that affects the order that transformations are being run because in the scenario described above, the domain class does not yet have the Entity annotation added to it so it isn’t being detected as a domain class in the same way it was with previous versions of Grails, at least in some circumstances. Relevant functional test: grails/grails3-functional-tests@a115c7928b4064 e6e03eb6a331f4be5d4dd800d6 fixes #10079
1 parent 48fdafb commit 94b47a7

File tree

2 files changed

+67
-10
lines changed

2 files changed

+67
-10
lines changed

grails-core/src/main/groovy/org/grails/compiler/injection/GrailsASTUtils.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -726,16 +726,24 @@ public static boolean isDomainClass(final ClassNode classNode, final SourceUnit
726726

727727
if (!isDomainClass && sourceNode != null) {
728728
final String sourcePath = sourceNode.getName();
729-
final File sourceFile = new File(sourcePath);
730-
File parent = sourceFile.getParentFile();
731-
while (parent != null && !isDomainClass) {
732-
final File parentParent = parent.getParentFile();
733-
if (parent.getName().equals(DOMAIN_DIR) &&
734-
parentParent != null &&
735-
parentParent.getName().equals(GRAILS_APP_DIR)) {
736-
isDomainClass = true;
737-
}
738-
parent = parentParent;
729+
final String grailsAppDirToLookFor = File.separator +
730+
GRAILS_APP_DIR + File.separator;
731+
final int indexOfGrailsAppDir = sourcePath.lastIndexOf(grailsAppDirToLookFor);
732+
if(indexOfGrailsAppDir >= 0) {
733+
final String pathToGrailsAppDir =
734+
sourcePath.substring(0, indexOfGrailsAppDir +
735+
grailsAppDirToLookFor.length());
736+
737+
final String pathToDomainDir = pathToGrailsAppDir +
738+
DOMAIN_DIR + File.separator;
739+
740+
final String className = classNode.getName();
741+
final String relativePathToDomainSourceFile =
742+
className.replace('.', File.separatorChar) + ".groovy";
743+
final String pathToDomainSourceFile = pathToDomainDir +
744+
relativePathToDomainSourceFile;
745+
746+
isDomainClass = new File(pathToDomainSourceFile).exists();
739747
}
740748
}
741749

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.grails.compiler.injection
2+
3+
import org.codehaus.groovy.ast.ClassNode
4+
import org.codehaus.groovy.control.SourceUnit
5+
import spock.lang.Issue
6+
import spock.lang.Specification
7+
8+
class GrailsASTUtilsSpec extends Specification {
9+
10+
@Issue('grails/grails-core#10079')
11+
void 'test domain class detection when the current source unit is associated with a controller'() {
12+
setup:
13+
File tmpDir = new File(System.getProperty('java.io.tmpdir'))
14+
15+
File projectDir = new File(tmpDir, "projectDir")
16+
17+
// create /projectDir/grails-app/domain/ under java.io.tmpdir
18+
File grailsAppDir = new File(projectDir, 'grails-app')
19+
File domainDir = new File(grailsAppDir, 'domain')
20+
21+
String packagePath = Something.package.name.replace('.' as char, File.separatorChar)
22+
23+
// create the source file that would contain the source for the
24+
// relevant domain class...
25+
File domainPackageDir = new File(domainDir, packagePath)
26+
domainPackageDir.mkdirs()
27+
File domainClassFile = new File(domainPackageDir, 'Something.groovy')
28+
domainClassFile.createNewFile()
29+
30+
// the controller source file doesn't really need to exist but we need a
31+
// fully qualified path to where it would be...
32+
File controllersDir = new File(grailsAppDir, 'controllers')
33+
File controllerPackageDir = new File(controllersDir, packagePath)
34+
File controllerClassFile = new File(controllerPackageDir,
35+
'SomethingController.groovy')
36+
37+
SourceUnit controllerSourceUnit = Mock()
38+
controllerSourceUnit.getName() >> controllerClassFile.absolutePath
39+
40+
expect: 'Something should be recognized as a domain because grails-app/domain/org/grails/compiler/injection/Something.groovy exists'
41+
GrailsASTUtils.isDomainClass(new ClassNode(Something), controllerSourceUnit)
42+
43+
and: 'SomethingElse should NOT be recognized as a domain because grails-app/domain/org/grails/compiler/injection/SomethingElse.groovy does NOT exist'
44+
!GrailsASTUtils.isDomainClass(new ClassNode(SomethingElse), controllerSourceUnit)
45+
}
46+
}
47+
48+
class Something {}
49+
class SomethingElse {}

0 commit comments

Comments
 (0)