Skip to content

Commit

Permalink
Add support for @ScaffoldService
Browse files Browse the repository at this point in the history
  • Loading branch information
codeconsole committed Sep 2, 2024
1 parent 1c6d9ce commit 15c9962
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package grails.plugin.scaffolding.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ScaffoldService {
Class<?> value() default Void.class;
Class<?> domain() default Void.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.grails.compiler.scaffolding

import grails.compiler.ast.AstTransformer
import grails.compiler.ast.GrailsArtefactClassInjector
import grails.plugin.scaffolding.annotation.ScaffoldService
import groovy.transform.CompileStatic
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.classgen.GeneratorContext
import org.codehaus.groovy.control.SourceUnit
import org.grails.compiler.injection.GrailsASTUtils
import org.grails.core.artefact.ServiceArtefactHandler
import org.grails.io.support.GrailsResourceUtils
import org.grails.plugins.web.rest.transform.ResourceTransform

import java.util.regex.Pattern

/**
* Transformation that turns a service into a scaffolding service at compile time if '@ScaffoldService'
* is specified
*
* @author Scott Murphy Heiberg
* @since 5.1
*/
@AstTransformer
@CompileStatic
class ScaffoldingServiceInjector implements GrailsArtefactClassInjector {

final String[] artefactTypes = [ServiceArtefactHandler.TYPE] as String[]
public static Pattern SERVICE_PATTERN = Pattern.compile(".+/" +
GrailsResourceUtils.GRAILS_APP_DIR + "/services/(.+)Service\\.groovy");

@Override
void performInjection(SourceUnit source, GeneratorContext context, ClassNode classNode) {
performInjectionOnAnnotatedClass(source, classNode)
}

@Override
void performInjection(SourceUnit source, ClassNode classNode) {
performInjectionOnAnnotatedClass(source, classNode)
}

@Override
void performInjectionOnAnnotatedClass(SourceUnit source, ClassNode classNode) {
def annotationNode = classNode.getAnnotations(ClassHelper.make(ScaffoldService)).find()
if (annotationNode) {
ClassNode serviceClassNode = annotationNode?.getMember("value")?.type
Class serviceClass = serviceClassNode?.getTypeClass()
ClassNode superClassNode = ClassHelper.make(serviceClass).getPlainNodeReference()
ClassNode currentSuperClass = classNode.getSuperClass()
if (currentSuperClass.equals(GrailsASTUtils.OBJECT_CLASS_NODE)) {
def domainClass = annotationNode.getMember("domain")?.type
if (!domainClass) {
domainClass = ScaffoldingControllerInjector.extractGenericDomainClass(serviceClassNode)
}
if (!domainClass) {
GrailsASTUtils.error(source, classNode, "Scaffolded service (${classNode.name}) with @ScaffoldService does not have domain class set.", true)
}
classNode.setSuperClass(GrailsASTUtils.nonGeneric(superClassNode, domainClass))
new ResourceTransform().addConstructor(classNode, domainClass, false)
} else if (!currentSuperClass.isDerivedFrom(superClassNode)) {
GrailsASTUtils.error(source, classNode, "Scaffolded services (${classNode.name}) cannot extend other classes: ${currentSuperClass.getName()}", true)
}
}
}

@Override
boolean shouldInject(URL url) {
return url != null && SERVICE_PATTERN.matcher(url.getFile()).find()
}
}

0 comments on commit 15c9962

Please sign in to comment.