Tagged: java-ee-7

Basic Java EE with Apache Maven


some-parent

다른 모듈들에서 사용할 dependency/plugin 등을 정리하는 모듈이다. java-ee-apiderby, h2 등의 메모리 DB, 그리고, eclipselink, hibernate-core, openejb-core 등이 정의되었다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>some.group</groupId>
  <artifactId>some-parent</artifactId>
  <version>0.1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <version.org.apache.tomee>7.0.2</version.org.apache.tomee>
    <version.org.eclipse.persistence>2.6.4</version.org.eclipse.persistence>
    <version.org.glassfish.jersey>2.25</version.org.glassfish.jersey>
    <version.org.glassfish.jersey.security>${version.org.glassfish.jersey}</version.org.glassfish.jersey.security>
    <version.org.glassfish.jersey.test-framework>${version.org.glassfish.jersey}</version.org.glassfish.jersey.test-framework>
    <version.org.wildfly.swarm>2017.1.1</version.org.wildfly.swarm>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.8</version>
      </dependency>
      <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.193</version>
      </dependency>
      <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.5</version>
      </dependency>
      <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derby</artifactId>
        <version>10.13.1.1</version>
      </dependency>
      <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>openejb-core</artifactId>
        <version>${version.org.apache.tomee}</version>
      </dependency>
      <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>eclipselink</artifactId>
        <version>${version.org.eclipse.persistence}</version>
      </dependency>
      <dependency>
        <groupId>org.gavaghan</groupId>
        <artifactId>geodesy</artifactId>
        <version>1.1.3</version>
      </dependency>
      <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.1-b08</version>
      </dependency>
      <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.2.6.Final</version>
      </dependency>
      <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.0.CR1</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.22</version>
      </dependency>
      <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>6.10</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-failsafe-plugin</artifactId>
          <version>2.19.1</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-javadoc-plugin</artifactId>
          <version>2.10.4</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-pmd-plugin</artifactId>
          <version>3.7</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>2.9</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.19.1</version>
        </plugin>
        <plugin>
          <groupId>org.bsc.maven</groupId>
          <artifactId>maven-processor-plugin</artifactId>
          <version>3.2.0</version>
        </plugin>
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>cobertura-maven-plugin</artifactId>
          <version>2.7</version>
        </plugin>
        <plugin>
          <groupId>org.jacoco</groupId>
          <artifactId>jacoco-maven-plugin</artifactId>
          <version>0.7.8</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

some-entities

Persistence-Unit 에 해당하는 모듈이다. 중요한 점으로 이 묘듈은 persistence.xml 파일을 포함하지 않는다는 것이다. persistence.xml 파일은 최종 application 에서 정의한다.

javaee-api

우선적으로 필요한 의존성은 javaee-api이다. provided scope로 선언한다.

  ...
  <groupId>some</groupId>
  <artifactId>some-entities</artifactId>
  <version>0.1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  ...

  <dependencies>
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  ...

</project>

BaseEntity.java

필요에 따라서 다른 entity들이 상속할 수 있는 기본클래스를 선언할 수도 있다.

@MappedSuperclass
public abstract class BaseEntity implements Serializable {

    // ...

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = COLUMN_NAME_ID, nullable = false, updatable = false)
    @XmlAttribute
    private Long id;

    // ...
}

metamodel generation

JPA Metamodel 들을 생성한다. maven-processor-pluginhibernate-jpamodelgen을 사용한다.

  ...
  <build>
    ...
    <plugins>
      ...
      <plugin>
        <groupId>org.bsc.maven</groupId>
        <artifactId>maven-processor-plugin</artifactId>
        <executions>
          <execution>
            <id>generate-metamodels</id>
            <goals>
              <goal>process</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
              <processors>
                <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
              </processors>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-jpamodelgen</artifactId>
            <version>5.2.6.Final</version>
          </dependency>
        </dependencies>
      </plugin>
      ...
    </plugins>
    ...
  </build>
  ...

src/test/resources/META-INF/persistence.xml

단위시험을 위해 in-memory database를 이용하는 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="somePU" transaction-type="RESOURCE_LOCAL">
    <provider>${provider}</provider>
    <class>com.mycompany.some.Some</class>
    ...
    <validation-mode>CALLBACK</validation-mode>
    <properties>
      <property name="javax.persistence.jdbc.driver" value="${javax.persistence.jdbc.driver}"/>
      <property name="javax.persistence.jdbc.url" value="${javax.persistence.jdbc.url}"/>
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
    </properties>
  </persistence-unit>
</persistence>

validation-modeCALLBACK으로 설정했으므로 validation framework을 추가해 줘야 한다.

    ...
    <dependency>
      <groupId>org.glassfish</groupId>
      <artifactId>javax.el</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <scope>test</scope>
    </dependency>
    ...

자 이제 h2, derby 등의 database와 eclipselinke, hibernate-core등의 JPA provider 등을 선택적으로 사용할 수 있는 profile 들을 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  ...
  <profiles>
    <profile>
      <id>derby</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <javax.persistence.jdbc.driver>org.apache.derby.jdbc.EmbeddedDriver</javax.persistence.jdbc.driver>
        <javax.persistence.jdbc.url>jdbc:derby:memory:someDB;create=true</javax.persistence.jdbc.url>
      </properties>
      <dependencies>
        <dependency>
          <groupId>org.apache.derby</groupId>
          <artifactId>derby</artifactId>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </profile>
    <profile>
      <id>h2</id>
      <properties>
        <javax.persistence.jdbc.driver>org.h2.Driver</javax.persistence.jdbc.driver>
        <javax.persistence.jdbc.url>jdbc:h2:mem:someDB</javax.persistence.jdbc.url>
      </properties>
      <dependencies>
        <dependency>
          <groupId>com.h2database</groupId>
          <artifactId>h2</artifactId>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </profile>
    <profile>
      <id>eclipselink</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
      </properties>
      <dependencies>
        <dependency>
          <groupId>org.eclipse.persistence</groupId>
          <artifactId>eclipselink</artifactId>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </profile>
    <profile>
      <id>hibernate</id>
      <properties>
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
      </properties>
      <dependencies>
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-core</artifactId>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </profile>
  </profiles>
</project>

기본적으로 derbyeclipselinkactiveByDefault 로 설정하였다. 다음과 같이 profile을 바꿔가면서 시험할 수 있다.

$ mvn -Ph2,eclipselink test
$ mvn -Pderby,hibernate test

some-services

some-resources

various ways to persist entities in jax-rs resources


references

via EJB

@Stateless
public class TestService {

    public Test persist(final Test test) {
        em.persist(test);
        return test;
    }

    @PersistenceContext(unitName = "pu")
    private EntityManager em;
}
@Path("/tests")
public class TestsResource {

    @POST
    @Path("/1")
    public void create1(final Test test) {
        ts.persist(test);
    }

    @EJB
    private TestService ts;
}

via PersistenceUnit

@POST
@Path("/2")
public void create2(final Test test) throws Exception {

    final EntityManager em = emf.createEntityManager();
    try {
        try {
            ut.begin();
            em.joinTransaction();
            em.persist(test);
            ut.commit();
        } catch (final Exception e) {
            ut.rollback();
            throw e;
        }
    } finally {
        em.close();
    }
}

@POST
@Path("/3")
public void create3(final Test test) throws Exception {

    try {
        ut.begin();
        final EntityManager em = emf.createEntityManager();
        try {
            em.persist(test);
        } finally {
            em.close();
        }
        ut.commit();
    } catch (final Exception e) {
        ut.rollback();
        throw e;
    }
}

@PersistenceUnit(unitName = "pu")
private transient EntityManagerFactory emf;

@Resource
private UserTransaction ut;

via PersistenceContext

@POST
@Path("/4")
public void create4(final Test test) throws Exception {

    try {
        ut.begin();
        em.joinTransaction();
        em.persist(test);
        ut.commit();
    } catch (final Exception e) {
        ut.rollback();
        throw e;
    }
}

@PersistenceContext(unitName = "pu")
private transient EntityManager em;

@Resource
private UserTransaction ut;

via PersistenceContext with Transactional Interceptors

@POST
@Path("/5")
@Transactional(rollbackOn = Exception.class)
public void create5(final Test Test) throws Exception {

    em.persist(test);
}

@PersistenceContext(unitName = "pu")
private transient EntityManager em;