<dependencies> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> <version>10.12.1.1</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina</artifactId> <version>8.0.28</version> <scope>runtime</scope> </dependency> </dependencies>
Entries tagged [jpa]
How to bind / lookup DataSource via JNDI without container
TweetPosted on Sunday Oct 25, 2015 at 10:58AM in Technology
While I prefer deploying JPA based apps to a Java EE container and test it via Arquillian as integration testing, some occasions won’t allow it and need arises that using a Servlet container or Java SE environment.
To supply information that required to connect the database (e.g. JDBC URL or credentials), it’s preferable to use JNDI rather than using DriverManager
or javax.persistence.jdbc.*
properties in persistence.xml
because using JNDI eliminates the need of managing such information in the application codebase, also it enables to use the container managed connection pool which is more flexible and scalable over another.
In such case, hard-coded JNDI name of a DataSource may be a problem in the time of testing because JNDI lookup doesn’t work without container as is. So we may need some considering of involve pluggable mechanism of acquiring java.sql.Connection
instance or creating persistence.xml
for unit testing.
These solutions are not much difficult to implement, but it’s preferable if JNDI lookup does work without container as well because it will decrease amount of testing specific code. In this posting, I’ll give you a complete example of looking up a DataSource without container using bare InitialContext
and the non-jta-datasource
persistence descriptor definition.
Environment
-
tomcat-catalina
artifact of Apache Tomcat 8.0.28: Enables binding a resource to JNDI context in Java SE environment -
Apache Commons DBCP 1.4: Supplies
BasicDataSource
class so make the example in database independent manner -
Apache Derby 10.12.1.1
-
EclipseLink 2.6.1
-
Oracle JDK8u60
Dependencies
persistence.xml
Note that the non-jta-data-source
is used with JNDI name of DataSource.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <non-jta-data-source>java:comp/env/jdbc/database</non-jta-data-source> <class>entity.Employee</class> <shared-cache-mode>NONE</shared-cache-mode> <properties> <property name="javax.persistence.schema-generation.database.action" value="create"/> <property name="eclipselink.logging.level" value="FINE"/> <property name="eclipselink.logging.parameters" value="true"/> </properties> </persistence-unit> </persistence>
Employee.java
This is a simple JPA entity class that will be used in testing.
@Entity public class Employee implements Serializable { @Id private Long id; private String firstName; private String lastName; // accessors omitted
Main.java
This binds a DataSource of Embedded in-memory Apache Derby database to java:comp/env/jdbc/database
, then lookup it via InitialContext
and EntityManagerFactory
.
public class Main { private static final String JNDI = "java:comp/env/jdbc/database"; public static void main(String[] args) throws Exception { bind(); lookup(); final EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU"); populate(emf); query(emf); } private static void bind() throws NamingException { System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory"); System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming"); final BasicDataSource ds = new BasicDataSource(); ds.setUrl("jdbc:derby:memory:myDB;create=true"); final Context context = new InitialContext(); try { context.createSubcontext("java:"); context.createSubcontext("java:comp"); context.createSubcontext("java:comp/env"); context.createSubcontext("java:comp/env/jdbc"); context.bind(JNDI, ds); } finally { context.close(); } } private static void lookup() throws NamingException, SQLException { final Context context = new InitialContext(); try { final DataSource ds = (DataSource) context.lookup(JNDI); try (final Connection cn = ds.getConnection(); final Statement st = cn.createStatement(); final ResultSet rs = st.executeQuery("SELECT CURRENT_TIMESTAMP FROM SYSIBM.SYSDUMMY1")) { while (rs.next()) { System.out.println(rs.getTimestamp(1)); } } } finally { context.close(); } } private static void populate(final EntityManagerFactory emf) { final EntityManager em = emf.createEntityManager(); try { final EntityTransaction tx = em.getTransaction(); tx.begin(); final Employee emp = new Employee(); emp.setId(1l); emp.setFirstName("Jane"); emp.setLastName("Doe"); em.persist(emp); tx.commit(); } finally { em.close(); } } private static void query(final EntityManagerFactory emf) { final EntityManager em = emf.createEntityManager(); try { System.out.println(em.find(Employee.class, 1l)); } finally { em.close(); } } }
Log
You can see the lookup()
method dumped CURRENT_TIMESTAMP
and EclipseLink successfully acquired a DataSource as follows.
2015-10-25 10:33:24.235 [EL Fine]: server: 2015-10-25 10:33:24.478--Thread(Thread[main,5,main])--Configured server platform: org.eclipse.persistence.platform.server.NoServerPlatform [EL Config]: metadata: 2015-10-25 10:33:24.633--ServerSession(1323434987)--Thread(Thread[main,5,main])--The access type for the persistent class [class entity.Employee] is set to [FIELD]. [EL Config]: metadata: 2015-10-25 10:33:24.654--ServerSession(1323434987)--Thread(Thread[main,5,main])--The alias name for the entity class [class entity.Employee] is being defaulted to: Employee. [EL Config]: metadata: 2015-10-25 10:33:24.656--ServerSession(1323434987)--Thread(Thread[main,5,main])--The table name for entity [class entity.Employee] is being defaulted to: EMPLOYEE. [EL Config]: metadata: 2015-10-25 10:33:24.666--ServerSession(1323434987)--Thread(Thread[main,5,main])--The column name for element [firstName] is being defaulted to: FIRSTNAME. [EL Config]: metadata: 2015-10-25 10:33:24.668--ServerSession(1323434987)--Thread(Thread[main,5,main])--The column name for element [lastName] is being defaulted to: LASTNAME. [EL Config]: metadata: 2015-10-25 10:33:24.668--ServerSession(1323434987)--Thread(Thread[main,5,main])--The column name for element [id] is being defaulted to: ID. [EL Info]: 2015-10-25 10:33:24.7--ServerSession(1323434987)--Thread(Thread[main,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3 [EL Fine]: connection: 2015-10-25 10:33:24.706--Thread(Thread[main,5,main])--Detected database platform: org.eclipse.persistence.platform.database.JavaDBPlatform [EL Config]: connection: 2015-10-25 10:33:24.714--ServerSession(1323434987)--Connection(1872973138)--Thread(Thread[main,5,main])--connecting(DatabaseLogin( platform=>JavaDBPlatform user name=> "" connector=>JNDIConnector datasource name=>java:comp/env/jdbc/database )) [EL Config]: connection: 2015-10-25 10:33:24.715--ServerSession(1323434987)--Connection(1465346452)--Thread(Thread[main,5,main])--Connected: jdbc:derby:memory:myDB User: APP Database: Apache Derby Version: 10.12.1.1 - (1704137) Driver: Apache Derby Embedded JDBC Driver Version: 10.12.1.1 - (1704137) [EL Config]: connection: 2015-10-25 10:33:24.715--ServerSession(1323434987)--Connection(1634387050)--Thread(Thread[main,5,main])--connecting(DatabaseLogin( platform=>JavaDBPlatform user name=> "" connector=>JNDIConnector datasource name=>java:comp/env/jdbc/database )) [EL Config]: connection: 2015-10-25 10:33:24.716--ServerSession(1323434987)--Connection(1740223770)--Thread(Thread[main,5,main])--Connected: jdbc:derby:memory:myDB User: APP Database: Apache Derby Version: 10.12.1.1 - (1704137) Driver: Apache Derby Embedded JDBC Driver Version: 10.12.1.1 - (1704137) [EL Info]: connection: 2015-10-25 10:33:24.747--ServerSession(1323434987)--Thread(Thread[main,5,main])--/file:/Users/kyle/src/jndi-se/target/classes/_myPU login successful [EL Fine]: sql: 2015-10-25 10:33:24.784--ServerSession(1323434987)--Connection(762809053)--Thread(Thread[main,5,main])--CREATE TABLE EMPLOYEE (ID BIGINT NOT NULL, FIRSTNAME VARCHAR(255), LASTNAME VARCHAR(255), PRIMARY KEY (ID)) [EL Fine]: sql: 2015-10-25 10:33:24.85--ClientSession(1027495011)--Connection(1688470144)--Thread(Thread[main,5,main])--INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME) VALUES (?, ?, ?) bind => [1, Jane, Doe] [EL Fine]: sql: 2015-10-25 10:33:24.877--ServerSession(1323434987)--Connection(640808588)--Thread(Thread[main,5,main])--SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID = ?) bind => [1] Employee{id=1, firstName='Jane', lastName='Doe'}
The complete source code can be obtained from my GitHub repository.
Working example of EclipseLink static weaving
TweetPosted on Saturday Oct 24, 2015 at 03:37AM in JPA
These days I’m using EclipseLink at work. It runs on Servlet containers, unfortunately not Java EE containers at there so I have experienced some difference between them. A significant one is class weaving. The dynamic weaving is enabled by default in Java EE containers but not for Java SE environment. Weaving is a prerequisite of using some important functions such as Lazy Loading but it doesn’t work for default Java SE environment. In Java SE environment, EclipseLink requires a special prerequisite that set an agent in the time of launching JVM, or use static weaving to enable Lazy Loading.
Static weaving offers some performance benefit over Dynamic weaving because it doesn’t require runtime weaving step. I think it’s preferable so I tried it over another.
Environment
-
EclipseLink 2.6.1
-
Apache Derby 10.12.1.1
-
Oracle JDK8u60
Projects
eclipselink-entity
This project contains three simple entity classes. Dept
has many Employee
, and Employee
has one Phone
.
Dept
@Entity public class Dept implements Serializable { @Id private Long id; private String deptName; @OneToMany(mappedBy = "dept") private List<Employee> employees; // accessors omitted
Employee
@Entity public class Employee implements Serializable { @Id private Long id; @ManyToOne(fetch = FetchType.EAGER) // default @JoinColumn(nullable = false) private Dept dept; private String firstName; private String lastName; @OneToOne(mappedBy = "employee", fetch = FetchType.LAZY) // overridden by LAZY private Phone phone; // accessors omitted
Note that the relation Employee.dept
is set to EAGER
, and Employee.phone
is set to LAZY
as FetchType.
Phone
@Entity public class Phone implements Serializable { @Id @OneToOne @JoinColumn(nullable = false) private Employee employee; private String phoneNumber; // accessors omitted
persistence.xml
The persistence descriptor requires a property called eclipselink.weaving
with the value static
to enable static weaving.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <exclude-unlisted-classes>false</exclude-unlisted-classes> <shared-cache-mode>NONE</shared-cache-mode> <properties> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/> <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:myDB;create=true"/> <property name="javax.persistence.jdbc.user" value="app"/> <property name="javax.persistence.jdbc.password" value="app"/> <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> <property name="eclipselink.weaving" value="static"/> <property name="eclipselink.logging.level" value="FINE"/> <property name="eclipselink.logging.parameters" value="true"/> </properties> </persistence-unit> </persistence>
pom.xml
The static weaving will be done by a convenient Maven plugin. Just put following plugin
definition in your pom.xml
and execute mvn clean install
.
<build> <plugins> <plugin> <groupId>de.empulse.eclipselink</groupId> <artifactId>staticweave-maven-plugin</artifactId> <version>1.0.0</version> <executions> <execution> <phase>process-classes</phase> <goals> <goal>weave</goal> </goals> <configuration> <persistenceXMLLocation>META-INF/persistence.xml</persistenceXMLLocation> <logLevel>FINE</logLevel> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.jpa</artifactId> <version>${eclipselink.version}</version> </dependency> </dependencies> </plugin> </plugins> </build>
eclipselink-example
This project is a client of the preceding eclipselink-entity
project. It has a Main
class which simply populates some records then fetches them.
public class Main { public static void main(String[] args) { EntityManagerFactory emf = null; try { emf = Persistence.createEntityManagerFactory("myPU"); EntityManager em = null; // Populating data try { em = emf.createEntityManager(); final EntityTransaction tx = em.getTransaction(); tx.begin(); Dept dept = new Dept(); dept.setId(1l); dept.setDeptName("Engineering"); dept.setEmployees(new ArrayList<>()); em.persist(dept); Employee emp = new Employee(); emp.setId(1l); emp.setFirstName("Jane"); emp.setLastName("Doe"); dept.getEmployees().add(emp); emp.setDept(dept); em.persist(emp); Phone phone = new Phone(); phone.setPhoneNumber("000-1111-2222"); phone.setEmployee(emp); emp.setPhone(phone); em.persist(phone); tx.commit(); } finally { if (em != null) { em.close(); } } System.out.println("<<< Populating done >>>"); try { em = emf.createEntityManager(); final Employee emp = em.find(Employee.class, 1l); System.out.println(emp.getFirstName() + " " + emp.getLastName()); // EAGER System.out.println(emp.getDept().getDeptName()); // LAZY System.out.println(emp.getPhone().getPhoneNumber()); } finally { if (em != null) { em.close(); } } } finally { if (emf != null) { emf.close(); } } } }
Here you can see the Phone
entity has lazily fetched while Dept
entity was eagerly fetched:
<<< Populating done >>> [EL Fine]: sql: 2015-10-24 03:18:23.389--ServerSession(1216590855)--Connection(1488298739)--Thread(Thread[main,5,main])--SELECT ID, FIRSTNAME, LASTNAME, DEPT_ID FROM EMPLOYEE WHERE (ID = ?) bind => [1] [EL Fine]: sql: 2015-10-24 03:18:23.408--ServerSession(1216590855)--Connection(1488298739)--Thread(Thread[main,5,main])--SELECT ID, DEPTNAME FROM DEPT WHERE (ID = ?) bind => [1] Jane Doe Engineering [EL Fine]: sql: 2015-10-24 03:18:23.413--ServerSession(1216590855)--Connection(1488298739)--Thread(Thread[main,5,main])--SELECT PHONENUMBER, EMPLOYEE_ID FROM PHONE WHERE (EMPLOYEE_ID = ?) bind => [1] 000-1111-2222
This example uses in-memory Apache Derby so you don’t need to set up any databases to execute this example. complete projects can be obtained from following GitHub repositories:
Also here’s build.gradle
example: https://github.com/lbtc-xxx/eclipselink-entity/blob/master/build.gradle
Tags: derby eclipselink jpa
Lean example of Tomcat 8 + Guice 4 + EclipseLink 2.6.0
TweetPosted on Tuesday Aug 04, 2015 at 07:26PM in Technology
I wrote a Lean example of Tomcat 8 + Guice 4 in previous entry. this time, I’ll try JPA(EclipseLink) integration with automatic transaction management.
The entire project which based on Maven can be obtained from My GitHub repository.
Prerequisites
For database connection, we’ll use a DataSource which is defined on Tomcat server. to define a Embedded Derby DataSource, This entry would help.
Dependencies
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>com.google.inject.extensions</groupId> <artifactId>guice-servlet</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>com.google.inject.extensions</groupId> <artifactId>guice-persist</artifactId> <version>4.0</version> </dependency> </dependencies>
web.xml
No changes against previous entry except addition of resource-ref
element.
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- taken from https://github.com/google/guice/wiki/Servlets --> <listener> <listener-class>guice.tomcat.MyGuiceServletConfig</listener-class> </listener> <filter> <filter-name>guiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>guiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <resource-ref> <res-ref-name>jdbc/derby</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
META-INF/persistence.xml
If you don’t want to use a DataSource on Tomcat, specify the connection information in javax.persistence.jdbc.*
properties instead of non-jta-data-source
.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myJpaUnit" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <non-jta-data-source>java:comp/env/jdbc/derby</non-jta-data-source> <class>guice.tomcat.MyEntity</class> <properties> <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> <property name="eclipselink.logging.level" value="FINE"/> <property name="eclipselink.logging.level.sql" value="FINE"/> </properties> </persistence-unit> </persistence>
MyGuiceServletConfig.java
The last two statements will take care of JPA integration.
public class MyGuiceServletConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new ServletModule() { @Override protected void configureServlets() { serve("/*").with(MyServlet.class); bind(MyService.class).to(MyServiceImpl.class); install(new JpaPersistModule("myJpaUnit")); filter("/*").through(PersistFilter.class); } }); } }
MyEntity.java
This is a very simple JPA entity which keeps only generated id
and ts
(a timestamp).
@Entity @NamedQuery(name = "MyEntity.findAll", query = "SELECT e FROM MyEntity e ORDER BY e.id DESC") public class MyEntity implements Serializable { @Id @GeneratedValue private Long id; @Column(nullable = false) @Temporal(TemporalType.TIMESTAMP) private Date ts; ... accessors are omitted
Service class
MyService.java
public interface MyService { void save(MyEntity e); List<MyEntity> findAll(); }
MyServiceImpl.java
Note that you need to annotate a method with @com.google.inject.persist.Transactional
if you need a transaction on it.
public class MyServiceImpl implements MyService { // Transactions doesn't start if EntityManager is directly injected via @Inject. // I have no idea why... // According to https://github.com/google/guice/wiki/JPA, // "Note that if you make MyService a @Singleton, then you should inject Provider<EntityManager> instead." @Inject private Provider<EntityManager> emp; @Override // @javax.transaction.Transactional is not supported yet. https://github.com/google/guice/issues/797 @com.google.inject.persist.Transactional public void save(MyEntity e) { EntityManager em = emp.get(); em.persist(e); } @Override public List<MyEntity> findAll() { return emp.get().createNamedQuery("MyEntity.findAll", MyEntity.class).getResultList(); } }
MyServlet.java
This servlet saves a MyEntity
with current timestamp, then fetches all of rows and returns them to the client on every request.
@javax.inject.Singleton public class MyServlet extends HttpServlet { @javax.inject.Inject private MyService myService; @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { MyEntity myEntity = new MyEntity(); myEntity.setTs(new Date()); myService.save(myEntity); PrintWriter writer = resp.getWriter(); writer.write("<html><body><ul>"); for(MyEntity e : myService.findAll()){ writer.write("<li>"); writer.write(e.toString()); writer.write("</li>"); } writer.write("</ul></body></html>"); } }
Test run
A row will be saved on every request as follows:
Tags: eclipselink guice jpa tomcat
Modifying persistence.xml to execute drop-and-create dynamically
TweetPosted on Monday Mar 23, 2015 at 03:19PM in JPA
I need that for Arquillian testing so I created an utility method for that.
Tags: arquillian jpa
Building environment specific artifacts with classifier
TweetPosted on Friday Mar 20, 2015 at 03:09PM in Maven
Consider following multi-module Maven project:
-
classifier
: The parent & aggregator project -
persistence
: A jar project which holds JPA entities and a persistence descriptor (persistence.xml
) -
web
: A war project which depends onpersistence
project
persistence
project contains following persistence descriptor:
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="javax.persistence.schema-generation.database.action" value="${javax.persistence.schema-generation.database.action}"/> </properties> </persistence-unit> </persistence>
I need to set javax.persistence.schema-generation.database.action
property as drop-and-create
for development environment, but none
for production environment. in such case, using profiles and filtering might be a solution, but its shortcoming is that we can hold only one (among environment specific builds) artifact in the local repository because these builds has same coordinate. it may bring unexpected result such as deploying development build to the production environment by some accident. in such case, using classifier would be a better solution.
Preparation
First, let’s enable resource filtering in persistence
project.
<build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <!-- Filter and copy resources under src/main/resources into target/classes (default location) --> <execution> <id>default-resources</id> <phase>process-resources</phase> <goals> <goal>resources</goal> </goals> <configuration> <filters> <filter>${basedir}/filters/dev.properties</filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build>
Then put filters/dev.properties
:
javax.persistence.schema-generation.database.action=drop-and-create
Set a dependency in web
project:
<dependencies> <dependency> <groupId>org.nailedtothex.examples.classifier</groupId> <artifactId>persistence</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
Add configurations for producing artifacts for production
Now we can make artifacts that holds filtered persistence.xml
for development environment. next, let’s add configurations for producing artifacts for production environment with prod
classifier.
Put following profile definition into persistence
project to make the project to produce both of development and production (with prod
classifier) artifacts:
<profile> <id>prod</id> <properties> <filteredResources>target/filtered-classes</filteredResources> </properties> <build> <plugins> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <!-- Filter and copy resources under src/main/resources into target/filtered-classes/prod --> <execution> <id>prod-resources</id> <phase>process-resources</phase> <goals> <goal>resources</goal> </goals> <configuration> <outputDirectory>${filteredResources}/prod</outputDirectory> <filters> <filter>${basedir}/filters/prod.properties</filter> </filters> </configuration> </execution> <!-- Copy classes under target/classes into target/filtered-classes/prod --> <!-- Existing files will not be overwritten. --> <!-- see http://maven.apache.org/plugins/maven-resources-plugin/resources-mojo.html#overwrite --> <execution> <id>copy-classes-prod</id> <phase>process-classes</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${filteredResources}/prod</outputDirectory> <resources> <resource> <directory>${project.build.outputDirectory}</directory> <filtering>false</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <executions> <!-- Create the production jar with files inside target/filtered-classes/prod --> <execution> <id>prod-jar</id> <phase>package</phase> <goals> <goal>jar</goal> </goals> <configuration> <classifier>prod</classifier> <classesDirectory>${filteredResources}/prod</classesDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile>
Also put filters/prod.properties
:
javax.persistence.schema-generation.database.action=none
Issue following command:
$ mvn clean install -P prod
Result:
... [INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ persistence --- [INFO] Building jar: /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT.jar [INFO] [INFO] --- maven-jar-plugin:2.6:jar (prod-jar) @ persistence --- [INFO] Building jar: /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT-prod.jar [INFO] [INFO] --- maven-install-plugin:2.4:install (default-install) @ persistence --- [INFO] Installing /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT.jar to /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT.jar [INFO] Installing /Users/kyle/src/classifier/persistence/pom.xml to /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT.pom [INFO] Installing /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT-prod.jar to /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT-prod.jar ...
You can see both of artifacts are installed as expected:
$ unzip -p /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT.jar META-INF/persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> </properties> </persistence-unit> </persistence> $ unzip -p /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT-prod.jar META-INF/persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="javax.persistence.schema-generation.database.action" value="none"/> </properties> </persistence-unit> </persistence>
So what is needed for web
project? put following profile as well:
<profile> <id>prod</id> <dependencies> <dependency> <groupId>org.nailedtothex.examples.classifier</groupId> <artifactId>persistence</artifactId> <version>1.0-SNAPSHOT</version> <classifier>prod</classifier> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <executions> <execution> <id>default-war</id> <phase>package</phase> <goals> <goal>war</goal> </goals> <configuration> <packagingExcludes>WEB-INF/lib/persistence-1.0-SNAPSHOT-prod.jar</packagingExcludes> </configuration> </execution> <execution> <id>prod-war</id> <phase>package</phase> <goals> <goal>war</goal> </goals> <configuration> <classifier>prod</classifier> <packagingExcludes>WEB-INF/lib/persistence-1.0-SNAPSHOT.jar</packagingExcludes> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile>
Then you will get both of artifacts installed after issuing mvn clean install -P prod
as follows:
$ unzip -l /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/web/1.0-SNAPSHOT/web-1.0-SNAPSHOT.war | grep persistence 3521 03-20-15 14:25 WEB-INF/lib/persistence-1.0-SNAPSHOT.jar $ unzip -l /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/web/1.0-SNAPSHOT/web-1.0-SNAPSHOT-prod.war | grep persistence 3513 03-20-15 14:25 WEB-INF/lib/persistence-1.0-SNAPSHOT-prod.jar