This is a follow up question to this SO Question. I am using jooq codegen for auto generation of jooq classes from jpa entities. I am planning to use jooq as a SQL query builder and execute the actual queries with JPA EntityManager. But jooq is generating the tables from entities with schema defaulted to PUBLIC.
For example if my query has to be
select SCHEMA_A.colA, SCHEMA_A.colB from SCHEMA_A.tableA;
jooq is generating
select PUBLIC.colA, PUBLIC.colB from PUBLIC.tableA;
This is making the query fail when I fire the following query because the schema is invalid.
entityManager.createNativeQuery(sqlString).getResultList();
What configuration do I need to add to make the autogenerated code contain the actual schema name?
Codegen:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>3.9.1</version>
<!-- The plugin should hook into the generate goal -->
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta-extensions</artifactId>
<version>3.9.1</version>
</dependency>
<dependency>
<groupId>com.yaswanth</groupId>
<artifactId>domain</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<configuration>
<!-- Generator parameters -->
<generator>
<database>
<name>org.jooq.util.jpa.JPADatabase</name>
<outputSchema>[SCHEMA_A]</outputSchema>
<properties>
<!-- A comma separated list of Java packages, that contain your entities -->
<property>
<key>packages</key>
<value>com.yaswanth.domain.entity</value>
</property>
</properties>
</database>
<target>
<packageName>com.yaswanth.domain.entity.jooq</packageName>
<directory>target/generated-sources/jooq</directory>
</target>
</generator>
</configuration>
</plugin>
</plugins>
</build>
jooq spring beans config
<bean id="dslContext" class="org.jooq.impl.DefaultDSLContext">
<constructor-arg ref="jooqConfig" />
</bean>
<bean id="jooqConfig" class="org.jooq.impl.DefaultConfiguration">
<property name="SQLDialect" value="MYSQL" />
<property name="dataSource" ref="myDataSource" />
<property name="settings" ref="settings"/>
</bean>
<bean id="settings" class="org.jooq.conf.Settings">
<property name="renderSchema" value="true" />
</bean>
The <outputSchema/> element cannot stand alone, it must be paired with an <inputSchema/> element. The reason is that if you leave out the <inputSchema/> element, then all schemata in your database are used for code generation, and it would be unclear what the standalone <outputSchema/> element means.
This misconfiguration should probably be reported as a warning in the log files: https://github.com/jOOQ/jOOQ/issues/6186
More information about the code generator's schema mapping feature here:
https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-catalog-and-schema-mapping
Note: This is how the jOOQ code generator behaves in general, the fact that the JPADatabase seems to be a bit particular here doesn't matter. Even with JPA annotated entities, you could have a database that includes several schemata if you specify the #Table(schema = "..."), for instance.
Related
My goal is to export database schema from Jpaconfiguration entities loaded in the classpath when building the project (create-schema.sql).
I found that using Hibernate tools exporters is the convenient way to do it using the ant task and the JpaConfiguration to autoLoookup for the persistent elements from Classpath.
Here is the plugin implementation I have tried:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>process-classes</id>
<phase>process-classes</phase>
<configuration>
<target>
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"/>
<hibernatetool destdir="target">
<classpath refid="maven.compile.classpath"/>
<jpaconfiguration />
<!-- Write all CREATE statements to a file. -->
<hbm2ddl drop="false" create="true" export="false"
outputfilename="schema-create.sql"
delimiter=";" format="true"/>
</hibernatetool>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-tools</artifactId>
<version>3.2.0.beta9a</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.12.Final</version>
</dependency>
</dependencies>
</plugin>
The problem Is that I am getting ClassNotFoundException Ejb3Configuration
[ERROR] [hibernatetool] java.lang.ClassNotFoundException: org.hibernate.ejb.Ejb3Configuration
From documentation but it didn't work for me either way :
ejb3configuration was the name used in previous versions. It still works but will display a warning telling you to use jpaconfiguration instead.
Solution inspired by Hibernate Tools Reference documentation :
Hibernate JPA based configuration (jpaconfiguration)
Hibernate Database schema exporter (hbm2ddl)
Any proposition please!
I am using Jooq Trial for generating code from SQL Server database as a poc. I use the below congifuration. However, it is not generating the information schema during compilation.
<plugin>
<groupId>org.jooq.trial</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>${jooq.version}</version>
<executions>
<execution>
<id>jooq-codegen</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<skip>${skip.jooq.generation}</skip>
</configuration>
</execution>
</executions>
<configuration>
<jdbc>
<driver>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver>
<url>${database.url}</url>
<user></user>
<password></password>
</jdbc>
<generator>
<name>org.jooq.codegen.JavaGenerator</name>
<database>
<name>org.jooq.meta.sqlserver.SQLServerDatabase</name>
<includes>.*</includes>
<excludes></excludes>
<!--<inputSchema></inputSchema> --> <!-- This will generate all schema of db, better to only generate the one
interested in -->
<inputCatalog>scm</inputCatalog>
<schemata>
<schema>
<inputSchema>dbo</inputSchema>
</schema>
<schema>
<inputSchema>INFORMATION_SCHEMA</inputSchema>
</schema>
</schemata>
</database>
<target>
<packageName>org.blackdread.sqltojava.jooq</packageName>
<directory>target/generated-sources/jooq</directory>
</target>
</generator>
</configuration>
<dependencies>
<dependency>
<groupId>org.jooq.trial</groupId>
<artifactId>jooq-meta</artifactId>
<version>${jooq.version}</version>
</dependency>
<dependency>
<groupId>org.jooq.trial</groupId>
<artifactId>jooq-codegen</artifactId>
<version>${jooq.version}</version>
</dependency>
<dependency>
<groupId>org.jooq.trial</groupId>
<artifactId>jooq</artifactId>
<version>${jooq.version}</version>
</dependency>
</dependencies>
</plugin>
Log:
[INFO] Generation finished: scm.dbo: Total: 1.493s, +0.333ms [INFO]
[INFO] Excluding empty schema : scm.INFORMATION_SCHEMA [INFO]
Removing excess files
But information_schema is available as views and it is returning me the necessary information too. I'm using windows authentication and not sa.
For historic reasons, jOOQ-meta's SQLServerDatabase only queries the sys.objects table, not the sys.all_objects table, to reverse engineer your database. This should be changed, of course. I have created a feature request for this:
https://github.com/jOOQ/jOOQ/issues/8827
It has been implemented for jOOQ 3.12
Workaround
In the meantime, you have these options:
Extend the SQLServerDatabase to adapt its queries to fetch rom all_objects, not from objects (this is a lot simpler with the professional edition than with the free trial, as you'll get the sources, and the right to patch the source code)
Use the JDBCDatabase, which queries JDBC's DatabaseMetaData, instead. This should return content from the sys and INFORMATION_SCHEMA schemas as well (but currently doesn't give access to e.g. stored procedures)
Use the generated INFORMATION_SCHEMA tables located in the jOOQ-meta module
I am using jooq codegen plugin in maven to generate code from xml schema file.
<configuration>
<generator>
<database>
<name>org.jooq.util.xml.XMLDatabase</name>
<properties>
<!-- Use any of the SQLDialect values here -->
<property>
<key>dialect</key>
<value>MYSQL</value>
</property>
<!-- Specify the location of your database file -->
<property>
<key>xml-file</key>
<value>${project.basedir}/src/main/resources/schema.xml</value>
</property>
</properties>
</database>
<generate>
<daos>true</daos>
<pojos>true</pojos>
<records>true</records>
<relations>true</relations>
<globalObjectReferences>false</globalObjectReferences>
</generate>
<target>
<!-- The destination package of your generated classes (within the
destination directory) -->
<packageName>com.generated.classes</packageName>
<!-- The destination directory of your generated classes. Using
Maven directory layout here -->
<directory>${project.basedir}/src/generated/classes</directory>
</target>
</generator>
</configuration>
Is there a solution to generate code from two different schema files. Example: schema-other.xml.
This is not yet supported by the XMLDatabase meta data source. The pending feature request is: https://github.com/jOOQ/jOOQ/issues/6260
There are workarounds, though:
Using separate configurations
If the two schemas / files are not linked, you can run two independent code generation runs. If you're using Maven, you could do it like this (see also this question):
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>3.9.4</version>
<executions>
<execution>
<id>first-generation</id>
<phase>generate-sources</phase>
<goals><goal>generate</goal></goals>
<configuration>
<generator>
<database>
<name>org.jooq.util.xml.XMLDatabase</name>
...
<properties>
<property>
<key>xml-file</key>
<value>file1.xml</value>
</property>
</properties>
</database>
...
<target>
<packageName>com.generated.classes.schema1</packageName>
<directory>${project.basedir}/src/generated/classes</directory>
</target>
</generator>
</configuration>
</execution>
<execution>
<id>second-generation</id>
<phase>generate-sources</phase>
<goals><goal>generate</goal></goals>
<configuration>
<!-- jOOQ configuration here -->
</configuration>
</execution>
</executions>
</plugin>
If you're using standalone code generation, just configure two separate runs.
Merging the XML files
You could of course merge the two XML files manually into a single one, e.g. by using XSLT for automatic merging, or manually.
I have user-guide which uses AsciiDoc it is very beautiful despite that I did not spend much time for it.
AsciiDoc plugins are awesome. So I want to pass my Maven final name in the user guide.
Question: How to do that?
<finalName>${project.artifactId}-${project.version}-${version.state}-r${buildNumber}</finalName>
My asciidoctor-maven-plugin configurations are:
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>${asciidoctor.maven.plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>${asciidoctorj.pdf.version}</version>
</dependency>
<!-- Comment this section to use the default jruby artifact provided by the plugin -->
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>${jruby.version}</version>
</dependency>
<!-- Comment this section to use the default AsciidoctorJ artifact provided by the plugin -->
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
<version>${asciidoctorj.version}</version>
</dependency>
</dependencies>
<configuration>
<sourceDirectory>src/docs/asciidoc</sourceDirectory>
<sourceDocumentName>manual.adoc</sourceDocumentName>
<!-- Attributes common to all output formats -->
<attributes>
<sourcedir>${project.build.sourceDirectory}</sourcedir>
</attributes>
</configuration>
<executions>
<execution>
<id>generate-pdf-doc</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<!-- Since 1.5.0-alpha.9 PDF back-end can use 'rouge' as well as 'coderay'
source highlighting -->
<sourceHighlighter>rouge</sourceHighlighter>
<attributes>
<icons>font</icons>
<pagenums/>
<toc/>
<idprefix/>
<idseparator>-</idseparator>
</attributes>
</configuration>
</execution>
</executions>
</plugin>
The official user guide cover this case in its Passing POM properties section:
It is possible to pass properties defined in the POM to the Asciidoctor processor. This is handy for example to include in the generated document the POM artifact version number.
This is done by creating a custom AsciiDoc property in the attributes section of the configuration. The AsciiDoc property value is defined in the usual Maven way: ${myMavenProperty}.
<attributes>
<project-version>${project.version}</project-version>
</attributes>
The custom AsciiDoc property can then be used in the document like this:
The latest version of the project is {project-version}.
Accordingly, you can hence apply the following to your existing configuration:
<configuration>
<sourceDirectory>src/docs/asciidoc</sourceDirectory>
<sourceDocumentName>manual.adoc</sourceDocumentName>
<!-- Attributes common to all output formats -->
<attributes>
<sourcedir>${project.build.sourceDirectory}</sourcedir>
<!-- the new property -->
<final-name>${project.build.finalName}</final-name>
</attributes>
</configuration>
Update 5: I've downloaded the latest Spring ToolsSuite IDE based on the latest Eclipse. When I import my project as a Maven project, Eclipse/STS appears to use the Maven goals for building my project. This means AspectJ finally works correctly in Eclipse.
Update 4: I have ended up just using Maven + AspectJ plugin for compile-time weaving, effectively bypassing Eclipse's mechanism.
Update 3: It seems AspectJ's Eclipse plug-in breaks Eclipse's ability to correctly Publish to Tomcat. Only by removing the AspectJ capability on a project can I get it to properly Publish again. Very annoying.
Update 2: I have this now working in Eclipse. It makes me very uncomfortable to say this, but I have no idea how I got it working from either Eclipse or Maven builds. It appears to be a compile issue rather than a run-time issue.
Update 1: It appears I've gotten this to work via Maven builds, but I have no idea how. Eclipse still doesn't work. The only thing I changed in the pom.xml was adding these (insignificant?) configuration parameters:
<source>1.6</source>
<complianceLevel>1.6</complianceLevel>
<verbose>true</verbose>
<showWeaveInfo>true</showWeaveInfo>
<outxml>true</outxml>
I'm actually worried that I have a repeat of this problem, where everything works inconsistently. I will keep this question updated as I learn more.
With regards to Eclipse, I made some progress by taking the binary aspects I wish to weave - in this case spring-aspects.jar - and copying it out of my classpath. I then add this now external jar to my Aspect Path. After doing this, Eclipse properly shows me AspectJ markers in my code. It's annoying that I can't just leave spring-aspects.jar in my Java Build Path which is maintained by Maven for me via the Maven plug-in. For some reason, however, the AspectJ plug-in doesn't see the binary aspects unless they're explicitly added to the Aspect Path.
Original Post: #Configurable is a Spring annotation that allows dependencies to be injected into objects instantiated external to Spring (for example, by Hibernate or some Factory class).
I was using this annotation previously with load-time weaving and it mostly worked. Occasionally I would boot up and nothing would get injected. This issue spawned this StackOverflow question. There weren't many answers, but most suggested that I try compile-time weaving instead due to greater reliability.
I installed the AspectJ plug-in for Eclipse and Maven. Both of these produce what appears to be properly compiled classes. I've opened up one of the classes in a text editor before AspectJ compilation and found no references to AspectJ. I opened it up after AspectJ compilation and both Eclipse and Maven generated versions have a reference to org.aspectj.weaver.MethodDeclarationLineNumber. This is why I assume it's being properly compiled. The problem is that once deployed, no dependencies get injected.
My Spring applicationContext.xml does include the following:
<context:spring-configured />
<context:component-scan base-package="com.myapp" />
Is the above all that's needed for classes marked #Configurable to have DI done? During the conversion from load-time weaving to compile-time weaving, I removed META-INF/aop.xml, <context:load-time-weaver /> from my applicationContext.xml, and Spring's Tomcat weaver from my context.xml.
How can I investigate this problem further? What are possible causes?
It works for us on maven using compile time weaving, try adding the following plugins:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerVersion>1.6</compilerVersion>
<fork>true</fork>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<configuration>
<source>1.6</source>
<target>1.6</target>
<verbose>false</verbose>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<configuration>
<source>1.6</source>
<target>1.6</target>
<verbose>false</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
</plugin>
Its done as two separate execution steps to allow you to add different aspect libraries for unit testing and compilation.
You'll also need the following dependency added for the spring-aspects library:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<scope>compile</scope>
</dependency>
I successfully configured load-time weaving in my app, if this is an alternative for you.
My environment:
JDK-1.6
Spring-2.5.6
JPA with eclipselink-1.1.0
Configuration details:
Spring XML configuration:
<context:annotation-config/>
<context:spring-configured/>
<context:load-time-weaver/>
<bean id="baseEntity" class="package.name.BaseEntity" scope="prototype">
<property name="historyHandler" ref="historyHandler" />
</bean>
<bean id="historyHandler" class="package.name.HistoryJpaHandler" scope="prototype">
<property name="historyDao" ref="historyDao" />
</bean>
<bean id="historyDao" class="package.name.HistoryJpaDao">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Spring annotations
#Configurable("baseEntity")
public abstract class BaseEntity
#Configurable("historyHandler")
public class HistoryJpaHandler extends SessionEventAdapter implements HistoryHandler
Java VM Parameter
<JAVA_HOME>/bin/java -javaagent:/full/path/to/spring-agent-2.5.6.jar
Instances of historyHandler and baseEntitty are created by ecliselink. historyHandler in baseEntitty and historyDao in historyHandler is set by load-timeweaving.
You can set the VM Parameter in Eclipse run configuration or in Tomcats catalina.sh/bat.
making a field of a #configurable class Autowired throws NullPointerException if you do not configure your spring properly for this annotation.
follow these steps to make #configurable annotations work properly
This method is called AspectJ build time weaving to inject spring beans to your non-spring-made classes.
First step is to install these plugins in eclipse:
From these two update sites install whatever eclipse suggests:
http://download.eclipse.org/tools/ajdt/43/update
http://dist.springsource.org/release/AJDT/configurator/
After installing,right-click on project and Do:
Configure > Convert to Aspectj
Maven > Update
Next, you need to add these to your pom.xml:
Under Dependencies Add:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
Under Plugins Add:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.5</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>1.7</source>
<target>1.7</target>
<Xlint>ignore</Xlint>
<complianceLevel>1.7</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>false</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>
</plugin>
Important: DO NOT use any <pluginManagment> tag under <build> tag.
your pom.xml needs to be something like this:
<project ....>
....
<dependencies>
<dependency>
....
</dependency>
....
</dependencies>
<build>
<plugins>
<plugin>
....
</plugin>
....
</plugins>
</build>
</project>
finally add <context:spring-configured /> to your spring application context config file.
Now you can annotate a POJO class as #Configurable and inject spring beans in it using #Autowired annotation. this way whenever you make a new instance of that POJO it will be configured (e.g. injected with dependencies) automatically.
As far as your Eclipse classpath issues are concerned, you might find this useful.
The m2eclipse plugin has an optional AJDT integration. The integration reads the aspectLibraries section of the aspectj-maven-plugin's configuration, and contributes the jars to Eclipse's Aspect Path.