Importing external domain classes into Grails - grails

I'm trying to create a sample project where domain classes are in an external normal groovy project and then used in a grails app (see https://github.com/ivanarrizabalaga/grails-domain-griffon):
book-svr
book-common
I'm also following the grails guide in order to get this (see http://grails.org/doc/latest/guide/hibernate.html) but the imported classes are not being recognized as domain classes.
The relevant parts:
External domain class:
package com.nortia.book
import grails.persistence.Entity
#Entity
class Book implements Serializable{
private static final long serialVersionUID = 1L;
String title
String author
static constraints = {
title blank:false
author blank:false
}
}
build.gradle:
....
dependencies {
// We use the latest groovy 2.x version for building this library
compile 'org.codehaus.groovy:groovy:2.1.7'
compile "org.grails:grails-datastore-gorm-hibernate4:3.0.0.RELEASE"
compile "org.grails:grails-spring:2.3.7"
....
In the grails app,
hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
'-//Hibernate/Hibernate Configuration DTD 3.0//EN'
'http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd'>
<hibernate-configuration>
<session-factory>
<mapping package='com.nortia.book' />
<mapping class='com.nortia.book.Book' />
</session-factory>
</hibernate-configuration>
BookController.groovy (I've tried an scaffolded and coded controller, and both failed):
...
class BookController{
static scaffold=Book
}
...
console.log (error):
ERROR ScaffoldingGrailsPlugin - Cannot generate controller logic for scaffolded class class com.nortia.book.Book. It is not a domain class!
Finally, suspicious log messages while initializing:
DEBUG cfg.Configuration - session-factory config [null] named package [com.nortia.book] for mapping
INFO cfg.Configuration - Mapping package com.nortia.book
WARN cfg.AnnotationBinder - Package not found or wo package-info.java: com.nortia.book
DEBUG cfg.Configuration - session-factory config [null] named class [com.nortia.book.Book] for mapping
INFO cfg.Configuration - Configured SessionFactory: null
So I'm wondering:
What's the missing piece?
According to the docs, looks like external 'domains' must be java classes but that's not a good option for my purpose.
I haven't try yet with a grails binary plugin instead of a groovy project, is it the way to go? (I need to use the domains in a griffon project that is why I opted this way first).

Finally solve it creating a 'sort of' a binary plugin manually.
Let's take a look step by step:
book-domain
Tree structure
src
main
groovy
demo
Book.groovy
resources
META-INF
grails-plugin.xml
build.gradle
Book.groovy
package demo
import grails.persistence.Entity
#Entity
class Book{
String title
static constraints = {
title blank: false
}
}
grails-plugin.xml
<plugin name='book-domain' version='1.0' grailsVersion='2.3 > *'>
<author>Ivan Arrizabalaga</author>
<title>External domains</title>
<description>An external domain plugin</description>
<documentation>http://grails.org/plugin/book-domain</documentation>
<type>demo.BookDomainGrailsPlugin</type>
<packaging>binary</packaging>
<resources>
<resource>demo.Book</resource>
</resources>
</plugin>
build.gradle
/*
* This build file was auto generated by running the Gradle 'init' task
* by 'arrizabalaga' at '5/26/14 12:34 PM' with Gradle 1.11
*
* This generated file contains a sample Groovy project to get you started.
* For more details take a look at the Groovy Quickstart chapter in the Gradle
* user guide available at http://gradle.org/docs/1.11/userguide/tutorial_groovy_projects.html
*/
// Apply the groovy plugin to add support for Groovy
apply plugin: 'groovy'
apply plugin: 'maven'
group = 'demo'
version = '1.0'
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'maven central' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
mavenCentral()
mavenLocal()
}
// In this section you declare the dependencies for your production and test code
dependencies {
// We use the latest groovy 2.x version for building this library
compile 'org.codehaus.groovy:groovy-all:2.1.9'
//compile "org.grails:grails-datastore-gorm-hibernate4:3.1.0.RELEASE"
compile "org.grails:grails-datastore-gorm-hibernate:3.1.0.RELEASE"
compile "commons-lang:commons-lang:2.6"
// We use the awesome Spock testing and specification framework
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'junit:junit:4.11'
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives sourcesJar
archives javadocJar
}
using it
Now the project can be built (gradle install to publish it into your local maven repo) and used (declaring the proper dependency) in any given project.
If the project that uses the jar is a Grails app it turns automatically the #Entity classes into real Domains.
Hope it helps.

Related

Should I use my package name for KMM SqlDelight config?

I am following this guide and in the first section of this step I have to do the following:
sqldelight {
database("AppDatabase") {
packageName = "com.jetbrains.handson.kmm.shared.cache"
}
}
Question is, should I use .handson. or .myPackageName. and why?
As guide from your link says
The packageName parameter specifies the package name for the generated Kotlin sources.
As with any kotlin file, you can specify any package name you want, but a good practice is to put all the files in the same module under the module package.
Let's say your module has the package name com.app.modules.shared. You can use the same package name for the generated database or some sub-path such as com.app.modules.shared.database.

How to implement a Groovy global AST transformation in a Grails plugin?

I'd like to modify some of my Grails domain classes at compilation time. I initially thought this was a job for Groovy's global ASTTransformation since I don't want to annotate my domain classes (which local transformers require). What's the best way to do this?
I also tried mimicking DefaultGrailsDomainClassInjector.java by creating my own class in the same package, implementing the same interfaces, but I probably just didn't know how to package it up in the right place because I never saw my methods get invoked.
On the other hand I was able to manually create a JAR which contained a compiled AST transformation class, along with the META-INF/services artifacts that plain Groovy global transformations require. I threw that JAR into my project's "lib" dir and visit() was successfully invoked. Obviously this was a sloppy job because I am hoping to have the source code of my AST transformation in a Grails plugin and not require a separate JAR artifact if I don't have to, plus I couldn't get this approach to work by having the JAR in my Grails plugin's "lib" but had to put it into the Grails app's "lib" instead.
This post helped a bit too: Grails 2.1.1 - How to develop a plugin with an AstTransformer?
The thing about global transforms the transform code should be available when the compilation starts. Having the transformer in a jar was what i did first! But as you said it is a sloppy job.
What you want to do is have your ast transforming class compile before others gets to the compilation phase. Here is what you do!
Preparing the transformer
Create a directory called precompiled in src folder! and add the Transformation class and the classes (such as annotations) the transformer uses in this directory with the correct packaging structure.
Then create a file called org.codehaus.groovy.transform.ASTTransformation in called precompiled/META-INF/services and you will have the following structure.
precompiled
--amanu
----LoggingASTTransformation.groovy
--META-INF
----services
------org.codehaus.groovy.transform.ASTTransformation
Then write the fully qualified name of the transformer in the org.codehaus.groovy.transform.ASTTransformation file, for the example above the fully qualified name would be amanu.LoggingASTTransformation
Implementation
package amanu
import org.codehaus.groovy.transform.GroovyASTTransformation
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.control.SourceUnit
#GroovyASTTransformation(phase=CompilePhase.CANONICALIZATION)
class TeamDomainASTTransformation implements ASTTransformation{
public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
println ("*********************** VISIT ************")
source.getAST()?.getClasses()?.each { classNode ->
//Class node is a class that is contained in the file being compiled
classNode.addProperty("filed", ClassNode.ACC_PUBLIC, new ClassNode(Class.forName("java.lang.String")), null, null, null)
}
}
}
Compilation
After implementing this you can go off in two ways! The first approach is to put it in a jar, like you did! and the other is to use a groovy script to compile it before others. To do this in grails, we use _Events.groovy script.
You can do this from a plugin or the main project, it doesn't matter. If it doesn't exist create a file called _Events.groovy and add the following content.
The code is copied from reinhard-seiler.blogspot.com with modifications
eventCompileStart = {target ->
...
compileAST(pluginBasedir, classesDirPath)
...
}
def compileAST(def srcBaseDir, def destDir) {
ant.sequential {
echo "Precompiling AST Transformations ..."
echo "src ${srcBaseDir} ${destDir}"
path id: "grails.compile.classpath", compileClasspath
def classpathId = "grails.compile.classpath"
mkdir dir: destDir
groovyc(destdir: destDir,
srcDir: "$srcBaseDir/src/precompiled",
classpathref: classpathId,
stacktrace: "yes",
encoding: "UTF-8")
copy(toDir:"$destDir/META-INF"){
fileset(dir:"$srcBaseDir/src/precompiled/META-INF")
}
echo "done precompiling AST Transformations"
}
}
the previous script will compile the transformer before others are compiled! This enable the transformer to be available for transforming your domain classes.
Don't forget
If you use any class other than those added in your classpath, you will have to precompile those too. The above script will compile everything in the precompiled directory and you can also add classes that don't need ast, but are needed for it in that directory!
If you want to use domain classes in transformation, You might want to do the precompilation in evenCompileEnd block! But this will make things slower!
Update
#Douglas Mendes mentioned there is a simple way to cause pre compilation. Which is more concise.
eventCompileStart = {
target -> projectCompiler.srcDirectories.add(0, "./src/precompiled")
}

Is there a way to inherit BuildConfig from a set of plugins to the current application?

Is there a 'builtin' way to share BuildConfig from plugins to a host application?
We have an application that is using homemade plugins and we need to copy/paste all special configuration (so everyting but dependency) settings from plugins to current app.
This is quite awful and it brings maintenance issue: when plugin A change its config, we need to update all project using this config.
I would like to be able to re-use as much as possible of the build settings from the plugin and just add specific settings (or replacement settings) to the main project BuildConfig.
The kind of properties we would like to share are:
common grails config block like:
grails.project.class.dir = "target/classes"
grails.project.test.class.dir = "target/test-classes"
grails.project.test.reports.dir = "target/test-reports"
grails.project.target.level = 1.6
grails.project.source.level = 1.6
specific plugin config:
grails.project.myplugin.config = { specials things }
some commons properties like dependencies version
In fact we want to have a kind of inheritance in the builconfig, a bit like when you define a parent project in a maven pom file.
In you're MyAppGrailsPlugin.groovy, you need to add a merge config function:
def doWithSpring = {
mergeConfig(application)
}
private void mergeConfig(GrailsApplication app) {
ConfigObject currentConfig = app.config.grails.fooConfig
ConfigSlurper slurper = new ConfigSlurper(Environment.getCurrent().getName());
ConfigObject secondaryConfig = slurper.parse(app.classLoader.loadClass("FooConfig"))
ConfigObject config = new ConfigObject();
config.putAll(secondaryConfig.fooConfig.merge(currentConfig))
app.config.grails.fooConfig = config;
}
def onConfigChange = { event ->
this.mergeConfig(application)
}
reference: http://swestfall.blogspot.ca/2011/08/grails-plugins-and-default-configs.html
I don't think you could merge the settings in plugin's BuildConfig to app's BuildConfig, because it will not be available in classpath to copy yet.
Moreover, your "special settings" (if they are not related to build) should be externalized and go to plugin specific *Config.groovy which can be easily amalgamated to host app by using the below in host app's Config.groovy:
grails.config.locations = ["classpath:${pluginSpecific}-config.groovy"]
Refer Externalized Configuration for details and Plugin Config plugin for more.
On the other hand, when behavior like parent object in maven pom is concerned, the approach to manipulate host app's build process from plugin is kind of scary. This has to be driven by host's build configuration and host can be idempotent about plugin's behavior.

#Resource Injection in jar in 'lib' of an ear; why doesn't that work?

I have simple ear (GF 4.0, JDK 7; sticking with EE6 for now)
The ear contains:
EJBJar
WAR
lib/Shared.jar
Shared has an #Qualifier (#UserDS) in it (it also has META-INF/beans.xml).
I have an #Producer like this:
package fhw.producers;
import fhw.qaulifiers.ListingDS;
import fhw.qaulifiers.UserDS;
import javax.annotation.Resource;
import javax.sql.DataSource;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Produces;
#Default
public class DataSourceProducer
{
#Resource(lookup = "Member")
private DataSource userDS;
public DataSourceProducer()
{
System.err.println("DataSourceProducer.DataSourceProducer -- CONSTRUCTION");
}
#Produces
#UserDS
public DataSource getUserDataSource()
{
System.err.println("******DataSourceProducer.getUserDataSource; am I null? " + (null == userDS) ) ;
return userDS;
}
}
I have a simple EJB (it has a beans.xml) that uses it via:
#Inject
#UserDS
private DataSource userDS;
QUESTION: When I put DataSourceProducer in the EJBJAR and deploy; my print statements come out and my #Resource resolves and everything is fine. When I put DataSourceProducer in the Shared.jar; the print statements still come out but the #Resource didn't work and the EJB NPE's on the null DS returned by producer method etc. In both tests the qualifier stayed in the Shared.jar. I have no DDs anyway where (well a web.xml for the war -- all else is implicit)
Part of me thinks this makes a bit of sense; #Resource is sort of EE oriented (or no?); and should mostly make sense within a EE deployable.
OTOH, why can't have I have hand-full of qualifiers and some producers in a Shared JAR in lib dir of an EAR that all EJBJars and WARs (in the EAR) can use?
Is there a way to make this work?
If you really want -- you can see an entire example here: https://github.com/fwelland/ResJect
I got the same issue on GF3, but the solution seems the same.
Remove the dependency from the lib directory and add it to the root of the ear.
Then add the following to the application.xml
<module><ejb>Shared.jar</ejb></module>
Tip: using maven-ear-plugin you can automatically add dependencies as modules to your ear
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<displayName>...</displayName>
<application-name>...</application-name>
<defaultJavaBundleDir>lib</defaultJavaBundleDir>
<!-- not generate application.xml! we include it ourselves -->
<generateApplicationXml>false</generateApplicationXml>
<modules>
<ejbModule>
<groupId>...</groupId>
<artifactId>Shared</artifactId>
<bundleFileName>Shared.jar</bundleFileName>
</ejbModule>
</modules>
</configuration>
</plugin>
Note that if you're using GlassFish 4, you're using Java EE 7, not Java EE 6. In order for your situation to work, you need to register your shared jar as a module in the application.xml, so that it knows to scan it.

How build Vaadin project with gradle?

I have gradle project (backend) and I want to add Vaadin-based frontend. But I haven't find any gradle-plugins for Vaadin.
While, as was already mentioned above, Vaadin app is a simple web application and does not require any additional plugins but "java" and "war" (and maybe "jetty" to run the app), currently there seems to be the first vaadin-specific gradle plugin available:
https://github.com/johndevs/gradle-vaadin-plugin
It will help you with Vaadin-specific task like building widgetsets, creating components skeletons, etc.
I think there is no a Vaadin plugin for Gradle but I have used Gradle in one of my Vaadin add-on projects: SplitButton. It's a project with sub-projects, widgetset compilation and it writes necessary jar manifest entries neebed by Vaadin Directory.
EDIT
Actually there is Gradle Vaadin plugin now - it allows you to easily build Vaadin projects with Gradle. It helps with the most tedious tasks when building a Vaadin project like building the widgetset and running development mode. It also helps you to quickly get started by providing tasks for project, component and theme creation:
https://github.com/johndevs/gradle-vaadin-plugin
You don't need a Vaadin plugin. A Vaadin application is simply a web application.The war plugin will suffice. If you want support for automatically creating the folder layout that Vaadin wants however, you might look into using the vaadin eclipse plugin found here:
http://vaadin.com/eclipse
If you are looking for deployment support, you can simply use the jetty plugin that comes with gradle or the tomcat plugin found here
https://github.com/bmuschko/gradle-tomcat-plugin
If you need to create custom widgets and compile them into a widgetset that's a GWT compile
https://vaadin.com/book/vaadin6/-/page/gwt.development.html#gwt.development.compiler
Note: The Vaadin7 Book no longer has the section on developing Gwt widgets.
There is a gradle plugin for GWT that could help with that. However, I've not needed a custom widget yet, so I haven't actually tried it.
https://github.com/markuskobler/gwt-gradle-plugin
This post:
Using Gradle with Vaadin
looks very comprehensive as far as Gradle+Vaadin setup goes. I'm also including a link to another Vaadin-based 'build.gradle' file I found on my travels, using Google's very useful 'filetype' search (see also the associated gradle.properties file).
JFYI that Google file search is:
filetype:<extension> <your search phrases>
Gradle can also be used to configure Eclipse and IntelliJ's project files by using a fragment such as the following (Eclipse natures can be 'found' by using the above Google file search for "project" extension and "natures" search, etc.):
//Template plugin - Great for project-layout setup - See http://tellurianring.com/wiki/gradle/templates
apply from: 'http://launchpad.net/gradle-templates/trunk/latest/+download/apply.groovy'
apply plugin: 'eclipse'
apply plugin: 'idea'
// if you want to distribute the gradle with your code
task('wrapper', type: Wrapper).configure {
gradleVersion = '1.0-milestone-8a'
}
def versionCompatibility = 1.6
//configurations.providedDependencies.extendsFrom configurations.gwt
eclipse {
project {
comment = ""
buildCommand "org.eclipse.jdt.core.javabuilder"
buildCommand "org.eclipse.wst.jsdt.core.javascriptValidator"
buildCommand "org.eclipse.wst.common.project.facet.core.builder"
buildCommand "org.eclipse.wst.validation.validationbuilder"
buildCommand "com.vaadin.integration.eclipse.widgetsetBuilder"
//buildCommand "org.eclipse.m2e.core.maven2Builder"
//buildCommand "org.maven.ide.eclipse.maven2Builder"
//buildCommand "com.google.gdt.eclipse.core.webAppProjectValidator"
//buildCommand "com.google.gwt.eclipse.core.gwtProjectValidator"
//buildCommand "com.google.gdt.eclipse.designer.GWTBuilder"
//Don't forget commas - no trailing
natures "org.eclipse.jdt.core.javanature",
"com.vaadin.integration.eclipse.widgetsetNature",
"org.eclipse.wst.jsdt.core.jsNature",
"org.eclipse.wst.common.project.facet.core.nature",
"org.eclipse.wst.common.modulecore.ModuleCoreNature",
"org.eclipse.jem.workbench.JavaEMFNature"
//"org.eclipse.m2e.core.maven2Nature",
//"org.maven.ide.eclipse.maven2Nature",
//"com.google.gwt.eclipse.core.gwtNature"
//"com.google.gdt.eclipse.designer.GWTNature",
//"ch.epfl.lamp.sdt.core.scalanature",
//"com.springsource.sts.grails.core.nature",
//"org.eclipse.jdt.groovy.core.groovyNature"
}
classpath {
containers "com.google.gwt.eclipse.core.GWT_CONTAINER"
//"com.springsource.sts.gradle.classpathcontainer"
//minusConfigurations=[configurations.gwt]
}
}
idea {
project {
jdkName = versionCompatibility
ipr {
withXml { provider ->
def node = provider.asNode()
// Set Gradle home
def gradleSettings = node.appendNode('component', [name: 'GradleSettings'])
gradleSettings.appendNode('option', [name: 'SDK_HOME', value: gradle.gradleHomeDir])
}
}
}
}
Cheers
Rich

Resources