Editing #java.persitence.Table in external jaxb-Binding - maven

I've set up a maven project to generate Java classes from a xsd-Schema. Firstly I configured the maven-hyperjaxb3-plugin (see the pom.xml snippet below), so that it can put the default JPA2 annotations in the entities. One of this annotations is #java.persitence.Table(name = "table_name"). I want to extend this annotation through an external global binding so that I can put the name of schema in it too. So that I would get #java.persitence.Table(name = "table_name", schema = "schema_name"). Is there a way to do this?
What about globally putting a prefix in the name of the table: #java.persitence.Table(name = "prefix_table_name"), any ideas how to do that?
Regards
Erzen
pom.xml snippet
<groupId>org.jvnet.hyperjaxb3</groupId>
<artifactId>maven-hyperjaxb3-plugin</artifactId>
<version>0.6.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<variant>jpa2</variant>
<extension>true</extension>
<roundtripTestClassName>EKMSEnvelopeRoundtripTest</roundtripTestClassName>
<args>
<arg>-Xinheritance</arg>
<arg>-XtoString</arg>
<arg>-Xannotate</arg>
</args>
<schemaExcludes>
<exclude>ekvaattributes.xsd</exclude>
</schemaExcludes>
</configuration>
bindings-xjc.xjb snippet
<jaxb:globalBindings localScoping="toplevel">
<!-- JPA-entities must be serializable -->
<xjc:serializable />
</jaxb:globalBindings>
<jaxb:bindings schemaLocation="schema.xsd"
node="/xs:schema">
<annox:annotate>
<!-- my attempt -->
<annox:annotate annox:class="javax.persistence.Table"
schema="schema_name">
</annox:annotate>
</annox:annotate>
<hj:persistence>
<hj:default-generated-id name="Hjid">
<orm:generated-value strategy="IDENTITY" />
</hj:default-generated-id>
</hj:persistence>
</jaxb:bindings>

Author of hyperjaxb3 here.
See #Stefan's answer, just add the schema="schema_name" attribute:
<orm:table name="item" schema="schema_name"/>
orm:table is actually a JPA XML element so that's documented in the JPA spec. :)
See this schema:
https://github.com/highsource/hyperjaxb3/blob/master/ejb/schemas/persistence/src/main/resources/persistence/orm/orm_1_0.xsd#L1814-L1815
I'm basically not inventing anything here.
You don't need JAXB2 Annotate Plugin for that, this works OOTB.
Here's an issue for the global prefix:
http://jira.highsource.org/browse/HJIII-87
Unresolved yet. Can be solved via custom naming now, but that's quite awkward.
https://github.com/highsource/hyperjaxb3/tree/master/ejb/tests/custom-naming
I agree, it would be nice to make it configurable.
Update How to do this globally:
<hj:default-entity>
<orm:table name="item" schema="schema_name"/>
</hj:default-entity>
But you'll also need to customize defaults for associations and so on. See he built-in defaults here:
https://github.com/highsource/hyperjaxb3/blob/master/ejb/plugin/src/main/resources/org/jvnet/hyperjaxb3/ejb/strategy/customizing/impl/DefaultCustomizations.xml

I'm not sure if this is possible, but try the element, maybe it has a 'schema' attribute, sadly it's not that well documented.
Regards,
Stefan
<jaxb:bindings schemaLocation="schema.xsd"
node="/xs:schema">
<annox:annotate>
<hj:persistence>
<hj:default-generated-id name="Hjid">
<orm:generated-value strategy="IDENTITY" />
</hj:default-generated-id>
</hj:persistence>
<!-- try this -->
<hj:entity>
<orm:table name="item"/>
</hj:entity>
</jaxb:bindings>
Source: http://confluence.highsource.org/display/HJ3/Customization+Guide

#lexicore Thnx for the help. After putting your suggestion in the right context it worked.
<hj:persistence>
<hj:default-entity>
<!-- no need to overwrite the default generated table names-->
<orm:table schema="schema_name" />
</hj:default-entity>
</hj:persistence>

You may also define a schema for all entities globally in orm file referenced from persistence.xml. There is no need to copy schema into every #Table annotation.
persistence.xml:
...
<persistence-unit name="MySchemaPU" transaction-type="JTA">
<mapping-file>META-INF/orm.xml</mapping-file>
And an orm.xml in META-INF folder:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>schema_name</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings

Related

How to configure Helidon application to use in-memory database for integration tests?

We are setting up a Helidon MP application that connects to a SQL database and exposes some endpoints for CRUD operations. I am facing issues when implementing the integration tests. Our objective is to have the application use the SQL database, but when running the tests use an in-memory database.
I've used this type of implementation on others frameworks and programing languages. The initial solution was to access the dependency injection container and change the configuration of the ORM (hibernate in this case) to use an in-memory database. Unfortunately I did not manage to do this.
The second approach was to configure another persistence.xml file in the test folder, that would override the one from main folder. Using on each of them a different jta-data-source, I would be able to configure separate connection credentials. I found out that this causes a ambiguous dependency and would fail.
content of src/resources/META-INF/persistence.xml
<persistence>
<persistence-unit name="dservice" transaction-type="JTA">
<jta-data-source>dsource</jta-data-source>
<class>.....</class>
.
.
.
<class>.....</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
</properties>
</persistence-unit>
</persistence>
content of test/resources/META-INF/persistence.xml
<persistence>
<persistence-unit name="dservice" transaction-type="JTA">
<jta-data-source>dsource_test</jta-data-source>
<class>.....</class>
.
.
.
<class>.....</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="jakarta.persistence.sql-load-script-source" value="META-INF/init_script.sql"/>
<property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
content of src/resources/META-INF/microprofile-config.properties
# used for build
oracle.ucp.jdbc.PoolDataSource.dsource.URL=jdbc:oracle:something
oracle.ucp.jdbc.PoolDataSource.dsource.connectionFactoryClassName=oracle.jdbc.pool.OracleDataSource
oracle.ucp.jdbc.PoolDataSource.dsource.user=some_user
oracle.ucp.jdbc.PoolDataSource.dsource.password=some_password
# used for in-memory testing
oracle.ucp.jdbc.PoolDataSource.dsource_test.URL=jdbc:h2:mem:depServerDb;DB_CLOSE_DELAY=-1
oracle.ucp.jdbc.PoolDataSource.dsource_test.connectionFactoryClassName=org.h2.jdbcx.JdbcDataSource
oracle.ucp.jdbc.PoolDataSource.dsource_test.user=db_user
oracle.ucp.jdbc.PoolDataSource.dsource_test.password=user_password
I added in main/resources/META-INF/persistence.xml another persistence unit with a different name and try to create the entity manager manually using Persistence.createEntityManagerFactory() and have a provider class to access the entity manager. Unfortunately this attempt also failed.
content of src/resources/META-INF/persistence.xml
<persistence>
<persistence-unit name="dservice" transaction-type="JTA">
<jta-data-source>dsource</jta-data-source>
<class>.....</class>
.
.
.
<class>.....</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
</properties>
</persistence-unit>
<persistence-unit name="dservice_test" transaction-type="JTA">
<jta-data-source>dsource_test</jta-data-source>
<class>.....</class>
.
.
.
<class>.....</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="jakarta.persistence.sql-load-script-source" value="META-INF/init_script.sql"/>
<property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
I ended up with a solution that I am not satisfied with. I kept the persistence.xml from scenario 3 and added a entity manager provider class in which I inject two entity managers, one for each persistence unit. In the test class I added a #AddConfig(key = "app.testing", value = "true"). This will make my entity manager provider to deliver the entity manager "depservice" when the application is running and "depservice-test" when I run "mvn test" command.
content of provider class
#ApplicationScoped
public class PersistenceUnitProvider {
#PersistenceContext(unitName = "dservice")
private EntityManager em_application;
#PersistenceContext(unitName = "dservice_test")
private EntityManager em_test;
private String testing = false;
#Inject
public PersistenceUnitProvider(#ConfigProperty(name = "app.testing") String testing){
this.testing = testing;
}
public EntityManager getPersistenceUnit(){
if(this.testing == "true"){
return em_test;
}
return em_application;
}
}
content of junit test class that will change app.testing property to true and use in-memory database
#HelidonTest
#AddConfig(key = "app.testing", value = "true")
class MainTest {
.
..
...
....
}
The issue is that this makes the application establish two connections when it's run or tested. Is there a better way to achieve this?
..............................................................................................................................................
UPDATE:
Following the solution Laird mentioned in the accepted answer, we are using the maven build process, that has phase triggers to add whatever config files needed to change the behavior of the helidon application.
We created a folder to store all the config files used for development, test and production, with the following structure:
_config
development
(files that use a local SQL database)
tests
(files that use a in memory database)
production
(files that use a development SQL database)
In the pom.xml file we switch the config files as needed for the different phases
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources-dev</id>
<phase>compile</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/META-INF</outputDirectory>
<resources>
<resource>
<directory>_config/development</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-resources-test</id>
<phase>test-compile</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/META-INF</outputDirectory>
<resources>
<resource>
<directory>_config/tests</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-resources-packaging</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/META-INF</outputDirectory>
<resources>
<resource>
<directory>_config/production</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
This will enable us, when we run "helidon dev", to use a localhost database. When we execute the tests, use a in-memory database. And when we package the application and want to run it on a server somewhere, use whatever database we need it to.
There are many, many, many things going on here. I'll try to keep it short; a full JPA tutorial is beyond the scope of this question and this website.
The short answer is: (1) in JPA, a persistence.xml is definitionally environment-specific, and (2) persistence.xmls don't "override" each other. When seen this way, the problem reduces to: I want two environments in the same project and can't figure out how to turn them on and off selectively.
There are a variety of (non-Helidon-specific) ways you can do this sort of thing:
Use the maven-resources-plugin to defer copying src/main/resources/META-INF/persistence.xml into target/classes/META-INF/ until after unit tests have run (so exclude persistence.xml from <resources> in your pom.xml and then bind the maven-resources-plugin:copy-resources goal to the prepare-package phase. Now src/test/resources/META-INF/persistence.xml will be in effect at unit test time, and your (untested) src/main/resources/META-INF/persistence.xml will be the one you deploy with.
Do amazing things with MicroProfile Config configuration profiles if the only thing you need to change is data source information, which is already external to a container-mode-JPA persistence.xml file, but from your example it seems that you need to change <property> elements as well.
Recognize that since persistence.xmls are inherently environment-specific, just don't include a src/main/resources/META-INF/persistence.xml at all in your library project, since a library project, by definition, is supposed to be used in a variety of environments. Instead, place a persistence.xml in its own "thin" project and combine that project with your library project to form an application. You can of course test these combinations in all sorts of other ways.
I would strongly recommend against adding test code to production bits, like you are doing with em_application and em_test. This may look simple at start but quickly go out of hand before you realize it.
Instead, try to retain only one line of code for testing and production. Have a single JPA persistence unit (em_application) in your PersistenceUnitProvider, persistence.xml and microprofile-config.properties. Stick to OracleDialect in test as well. Make a second copy of your META-INF/microprofile-config.properties under your JUnit test directory and retain the H2 configuration in the test copy. You would additionally have to shift your init_script.sql to the H2 connection URL to orchestrate the setup, since persistence.xml can no longer carry H2 configuration.
The HelidonTest application should pick up the test copy of mp-config properties file and the persistence until would automatically now work with H2.

Whats the correct way to allow different jdbc drivers for deployed applications on JBoss / Wildfly?

My setting is the following:
I got an application, which I deploy in /standalone/deployments
The jboss-deployment-structure.xml of my deployment in /standalone/deployments looks the following:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<dependencies>
[...]
<module name="org.postgresql"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
To drop the jboss-deployment-structure.xml completely (because it must not be used if there are no classloading issues), doesn't work. I use more dependencies (keycloak) beside the driver, which can't be found then.
My module.xml in my module org/postgresql/main looks like this (like described in https://www.keycloak.org/docs/4.8/server_installation/index.html#package-the-jdbc-driver)
<?xml version="1.0" encoding="UTF-8"?>
<module name="org.postgresql" xmlns="urn:jboss:module:1.5">
<resources>
<resource-root path="postgresql-42.2.5.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
My requirement is, to allow different types of jdbc-drivers, e.g. postgres, oracle, mssql.
First option:
I can change my jboss-deployment-structure.xml to
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<dependencies>
[...]
<module name="org.postgresql" optional="TRUE"/>
<module name="com.oracle.ojdbc6" optional="TRUE"/>
[...]
</dependencies>
</deployment>
</jboss-deployment-structure>
(added the optional-parameter)
Then I have to allow all drivers explicitly. Seems to be not the best way.
The idea comes from the standard documentation.
Second option:
I change my module-path to driver/jdbc/main (instead of org/postgres/main) and the module.xml to
<module name="driver.jdbc" xmlns="urn:jboss:module:1.5">
[...]
</module>
(changed name of module)
and go with the module-reference in my jboss-deployment-structure.xml like
<jboss-deployment-structure>
[...]
<module name="driver.jdbc"/>
[...]
</jboss-deployment-structure>
Now I force my customers to name the driver-module like I proposed. They can't name the module like mentioned in every standard-documentation.
The idea comes from this question.
I am doing this in context of a keycloak installation with a self-implemented User-federation to access a separate (legacy) user-database. Therefore dropping the jboss-deployment-structure.xml is no option as mentioned above.
Whats the correct way to achieve my goal of being flexible with the jdbc-driver?
EDIT: mentioned, dropping jboss-deployment-structure.xml is not working.
Keycloak have a very well designed container. You can get inspiration from it for your deployment. Just take a look at how the Dockerfile installs database driver modules and later how to activate those modules using jboss_cli.
Of course, if you can, maybe you can use the container instead. Just make sure to include the module.xml for your driver and activate it on start-up by providing your own entrypoint.
I would suggest you should install all database drivers individually as modules. Individual modules will help you to track and upgrade driver jars easily in the future.
As long as you don't have any classloading problems with your application you don't need to mention these drivers in the jboss-deployment-structure.xml file. They are static modules and will be loaded on server startup.
Moreover, after installing the driver modules, you have to add entries in the standalone.xml file. For example, if I have installed Oracle driver then
<driver name="oracle" module="com.oracle">
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
</driver>
within the tag.
Add a datasource definition within the tag (next to ExampleDS):
<datasource jndi-name="java:/[NAME]" pool-name="OracleDS" enabled="true">
<connection-url>jdbc:oracle:thin:#[HOST_NAME]:1521:[SID]</connection-url>
<driver>oracle[has to match the driver name]</driver>
<pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>5</max-pool-size>
<prefill>true</prefill>
</pool>
<security>
<user-name>[USER]</user-name>
<password>[PWD]</password>
</security>
</datasource>
At least I went with a hybrid solution of my two above mentioned approaches for the jboss-deployment-structure.xml like as follows
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.postgresql" optional="TRUE"/>
<module name="com.oracle.ojdbc6" optional="TRUE"/>
[...]
<module name="driver.jdbc" optional="TRUE"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
I listed all the relevant database divers as optional modules and listed another one with flexible naming if a driver is desired, which is not mentioned in the list above.

maven plugin - jaxb - Creating JAXB Classes

I am using JAXB plugin and need to generate classes for at least a dozens schema.
How would i dynamically create packages corresponding to each schema ?
schema 1 -> package x.y.z.schema1
schema 2 -> package x.y.z.schema2.....
The style mentioned in JAXB2 Maven plugin makes your pom.xml very messy.
Suggested by JAXb2 Help Page :
<execution>
<id>xjc-schema1</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<schemaFiles>schema1.xsd</schemaFiles>
<packageName>com.example.foo</packageName>
</configuration>
</execution>
<execution>
<id>xjc-schema2</id>
Alternatively I think a workaround would be to store this configs in a separate xml file but I dont know how to do include this in maven
Did you try using binding file?
I used to do that with a binding file like:
<?xml version="1.0"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
jaxb:extensionBindingPrefixes="inheritance" jaxb:version="2.1">
<jaxb:bindings schemaLocation="../xsd/mySchema1.xsd"
node="/xsd:schema">
<jaxb:schemaBindings>
<jaxb:package name="my.package.schema1" />
</jaxb:schemaBindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="../xsd/mySchema2.xsd"
node="/xsd:schema">
<jaxb:schemaBindings>
<jaxb:package name="my.package.schema2" />
</jaxb:schemaBindings>
</jaxb:bindings>
</jaxb:bindings>
So that in your pom you specify only the folder of all XSD and the path to the Binding file

Resolving type definitions from imported schema in XJC fails

I've got this API using JAXB to conveniently use object models, generated from XML Schemas by the XJC (XML-to-Java) compiler, through named references. It abstracts the creation of JAXB contexts and finding ObjectFactory methods away by all sorts of background magic and reflection. The basic gist of it is that you'd always define one general schema, and then any number (may also be 0) of schemas "extending" that general one, each resulting in its own data model. The general schema carries the reusable definitions, the ones extending it use those to compose their own models.
I've now run into the situation where I'd like to reuse the general schema for more than one project. The general type definitions should remain the same across projects, and some code will be built against the abstract classes generated from those. So I'd need to first generate classes for some generic schema, then generate those extending and using them separately. I'm using Maven for my build process.
The problem I'm running into is resolving type definitions from that generic schema in the extending schemas.
Suppose my generic schema is named "general.xsd" and looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/general"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<!-- Element (will usually be root) -->
<xs:element name="transmission" type="gen:Transmission" />
<!-- Definition -->
<xs:complexType name="Transmission" abstract="true">
<xs:sequence>
<!-- Generic parts of a transmission would be in here... -->
</xs:sequence>
</xs:complexType>
</xs:schema>
Next to that there's a bindings file to do some naming customization and set the package name for the output:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for the general schema -->
<bindings schemaLocation="general.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.general"/>
</schemaBindings>
<bindings node="//xs:complexType[#name='Transmission']">
<!-- Some customization of property names here... -->
</bindings>
</bindings>
I'd then have the next bit in the POM of that project to generate the Java classes:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>true</episode>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
As you can see, I'm using the JAXB2.1 Maven plugin. I've set the option to have an episode file generated for step-wise compilation. The option to remove previous output was for a bug workaround; all it does is make sure everything's cleaned up first so recompilation is forced.
So far so good. That project compiles without a hitch. It should be noted that apart from the generated Java classes, I also package the schemas into the resulting jar file. So those are available on the classpath! The sun-jaxb.episode file is in the META-INF, as it should be.
Then I start on the project that uses schemas which will extend the above, by first importing it. One of the "subtypes" could look like this (I'll call it sub.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/sub"
xmlns:sub="http://www.foobar.com/sub"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xs:import namespace="http://www.foobar.com/general" />
<!-- Definition -->
<xs:complexType name="SubTransmission">
<xs:complexContent>
<xs:extension base="gen:Transmission">
<xs:sequence>
<!-- Additional elements placed here... -->
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Again, there's a bindings file:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for sub type -->
<bindings schemaLocation="sub.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.sub"/>
</schemaBindings>
</bindings>
</bindings>
And here's the bit from the POM of this project that takes care of the XJC generation:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>false</episode>
<catalog>${basedir}/src/main/resources/com/foobar/schemas/catalog.cat</catalog>
<episodes>
<episode>
<groupId>com.foobar</groupId>
<artifactId>foobar-general-models</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</episode>
</episodes>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
Originally, all the schemas were in a single folder and I had the schemaLocation attribute in the import set to general.xsd, which worked fine. But now that things are separated across projects, I run into problems. The first issue was that the other schema could not be found. I've resolved this by taking the schemaLocation attribute out of the <xs:import /> element, keep only the namespace attribute and adding a catalog file (catalog.cat) which you can see referenced in the above POM extract. Its contents are:
PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"
This seems to work, since I no longer get an error that states the schema cannot be found. But for some reason, resolving the actual type definitions from the imported schema continues to fail. Here's the exception:
Error while parsing schema(s).Location [ file:/C:/NetBeans_groups/Test/SubModelBundle/src/main/resources/com/foobar/schemas/sub.xsd{...,...}].
org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'gen:Transmission' to a(n) 'type definition' component.
Here's what I tried so far:
Use a catalog file. Partially successful, since the imported schema can now be found.
Have the compilation for the general schema generate an episode file and use this for the compilation of the sub schema. Doesn't appear to make a difference, although this should only play a role once the type was resolved, so I don't think this is important yet.
Use a different JAXP (note: not JAXB, JAXP) implementation. It did use a different one, because I could see that in the exception's stack trace, but the end result is the same.
Use the maven-jaxb22-plugin instead of 21. No difference.
Looking around online, it seems people have been running into this issue since at least 2006 and it might be related to some Xerces resolver problems. I hope that this is not some bug that's been lurking around for 6 years without anyone caring to fix it. Does someone else have some suggestions? Maybe someone ran into the same problem and found a solution? The only workaround I can think of is to use 'svn:externals' to drag the general schema into the sub project and just regenerate the classes there, but it's dirty and will only work when you can connect to our svn repo.
Much thanks in advance for reading this long post. Do keep in mind that I've taken all of the above from existing projects and replaced some namespaces and other things for anonymity, so some typos are possible.
This answer was edited. Before, I had a solution using a custom catalog resolver. However, I've found the actual problem now. The explanation follows. For the TL;DR version that provides the solution, scroll to the bottom of this answer.
The problem is with the catalog file. Note how it had this line:
PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"
What does that say? It says that if the public ID http://www.foobar.com/general is encountered, the system ID for the schema is classpath:/com/foobar/schemas/general.xsd. So far so good. If we take the schemaLocation attribute out of our <xs:import /> elements, the only thing that remains is the public ID (namespace URN) and the catalog file tells us where to find the schema for it.
The problem occurs when that schema then uses <xs:include /> elements. They include schema files with the same target namespace. They specify a system ID (relative location). So you'd expect that to be used for resolution. However, logging the calls to the catalog resolver reveals that requests are made for resolution with both the public ID (namespace) and system ID (relative location). And that's where it goes wrong. The public ID is given preference because of the binding in the catalog file. And that leads us straight to the general.xsd file again.
Say for example that the general schema is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/general"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<!-- Including some definitions from another schema in the same location -->
<xs:include schemaLocation="simple-types.xsd" />
<!-- Remaining stuff... -->
</xs:schema>
And that a schema using that one is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/sub"
xmlns:sub="http://www.foobar.com/sub"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xs:import namespace="http://www.foobar.com/general" />
<!-- Remaining stuff... -->
</xs:schema>
When XJC is parsing that last schema, this is happening:
Parsing local definitions.
Encounters reference to definition from imported schema.
Checks import, finds no system ID, only public ID (http://www.foobar.com/general).
Checks catalog(s).
Finds binding of public ID to classpath:/com/foobar/schemas/general.xsd.
Parsing definitions in imported schema.
Encounters reference to definition from included schema (simple-types.xsd).
Checks include, finds system ID.
Checks catalog(s) for the system ID, but the public ID is implicit.
Finds binding of public ID to classpath:/com/foobar/schemas/general.xsd, which takes preference over system ID.
Resolution of included schema definitions fails.
The details for the order in which resolution is attempted are described in the OASIS spec for XML catalogs: https://www.oasis-open.org/committees/entity/spec.html#s.ext.ent. It takes a bit of interpretation, but you'll find that if the preferred method of resolution is the public IDs, those will take precedence when bound in the catalog file even if there is a system ID.
The solution, then, is to specify that system IDs are the preferred method of resolution, not provide system IDs in the imports so that the catalog's public ID binding is used and relying on the relative system IDs from the includes. In the OASIS XML catalog format, you can use attribute prefer="system". In the OASIS TR9401 catalog format, you can use OVERRIDE no. Apparently the default is public/yes.
So my catalog file then becomes:
OVERRIDE no
PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"
Now the regular catalog resolver works fine. I no longer need the custom one. However, I wouldn't have guessed that the public ID is still used for resolution when including schemas and takes precedence over the system ID. I'd have thought the public ID would only be used for imports, and that the system ID would still be considered if resolution failed. Only adding some logging to the custom resolver revealed this.
The short answer: add OVERRIDE no as the first directive in your TR9401 catalog file, or attribute prefer="system" to an XML catalog file. Don't specify schemaLocation in <xs:import /> directives, but bind the namespace to the proper schema location in the catalog file. Make sure <xs:include /> uses a relative path to the included schema.
Another interesting thing: the catalog resolver used by XJC can handle not just classpath: URIs, but also maven: URIs, which work relative to a Maven artefact. Pretty useful if you're using that as your build tool.
http://confluence.highsource.org/display/MJIIP/User+Guide#UserGuide-Usingcatalogs
Using Maven 2.2.1 works for me using org.jvnet.jaxb2.maven2.resolver.tools.ClasspathCatalogResolver.
Here's a sample configuration:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>executionId</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>src/main/resources/META-INF/schemas</schemaDirectory>
<generatePackage>com.company.project.data</generatePackage>
<bindingDirectory>src/main/jaxb</bindingDirectory>
<catalog>src/main/jaxb/catalog.cat</catalog>
<catalogResolver>org.jvnet.jaxb2.maven2.resolver.tools.ClasspathCatalogResolver</catalogResolver>
<verbose>false</verbose>
<extension>true</extension>
<episodes>
<episode>
<groupId>com.company.project</groupId>
<artifactId>xsd-common-types</artifactId>
<version>${xsd-common-types.version}</version>
</episode>
</episodes>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.company.project</groupId>
<artifactId>xsd-common-types</artifactId>
<version>${xsd-common-types.version}</version>
</dependency>
</dependencies>
</plugin>
Making this configuration work with Maven 3 results in a org.xml.sax.SAXParseException

Spring module in JBoss 7

I'm trying to set up Spring 3.0.6 libraries as a module in JBoss 7.
I have all of the jars in modules/org/springframework/main along with the following module.xml
<module xmlns:"urn:jboss:module:1.0" name="org.springframework">
<resources>
<resource-root path="org.springframework.beans-3.0.6.RELEASE.jar"/>
...
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.servlet.api"/>
<module name="org.apache.commons.logging"/>
</dependencies>
</module>
I added org.springframework to the Dependencies line in my MANIFEST.MF
When I deploy the app the following exception is thrown while parsing my spring-servlet.xml file (sorry, this is from a system that is not networked)
SAXParseException: ... Cannot find the declaration of element 'beans'
My first thought was that the module is not being used but if I remove org.springframework from my Dependencies line it fails to find org.springframework.web.context.ContextLoaderListener
Everything works fine if I put the jars in WEB-INF/lib instead of using the module.
spring-servlet.xml contains the following schema reference
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
so I put spring-beans-3.0.xsd in the same directory as spring-servlet.xml and modified the xml to
http://www.springframework.org/schema/beans spring-beans-3.0.xsd
but still no luck.
Anybody have an idea of why the class files are found but the xsd files are not?
Just in case the link that was given in the comments goes away, the problem is that
Problem:
The namespace configuration files are in META-INF, but that directory
is not visible (nor is it configurable via
jboss-deployment-structure.xml)
Solution:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
<deployment>
<dependencies>
<module name="org.apache.commons.logging"/>
<module name="org.springframework" >
<imports>
<include path="META-INF**"/>
<include path="org**"/>
</imports>
</module>
</dependencies>
</jboss-deployment-structure>
Was facing the exact same issue. Had set up a spring module on JBoss 7 and then when deploying my application, was facing the below warning:
Failed to read schema document
'http://www.springframework.org/schema/beans/spring-beans-3.2.xsd'
I understood the spring context file was unable to access the schema definitions from the spring jars, after reading the link in the comments above. And hence, the application was not getting deployed. But the solution given there did not work for me. But the below code in the jboss-deployment-structure.xml resolved the issue.
Solution
<module name="org.springframework.spring" meta-inf="export" export="true" />
Added meta-inf="export" attribute.

Resources