DataNucleus starting with Gradle

Introduction

This is the 11th day article of Java Advent Calendar 2016.

It all started when I was a Gradle skier and wanted to use Google Cloud SQL with Google Container Engine on Gradle. After that, I hit some walls, so I decided to write a little of them, including the meaning of a memorandum.

Google Cloud SQL is a function of Google Cloud Platfrom and is a MySQL compatible DB. Google Container Engine is also a feature of Google Cloud Platform, simply a Docker host. There are many misunderstandings, so please refer to specialists, specialized books, and specialized pages in this area.

What is JDO and Datanucleus?

To briefly explain JDO, it is a mechanism that allows Java classes to be stored in the DB as they are. It is said that using JDO to hold the state of a class is expressed as persistence. In this article, I'll leave the structure aside and make it available first.

DataNucleus is a JPA and JDO implementation and is also commonly used on Google App Engine. Therefore, when you search the Web for DataNucleus, you will find many articles about App Engine, which can be a little confusing. The official page is here. http://www.datanucleus.org/

In this article, I would like to introduce DataNucleus 5.0.3, which is one step ahead of the latest.

Gradle project

Now, I would like to create a Gradle project. I'm not good at explaining, so I'd like to talk in code.

build.gradle


buildscript {
  repositories {
    jcenter()
  }
}

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'net.leak4mk0.test.datanucleus.Main'

[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'

repositories {
    jcenter()
}

dependencies {
  // JDO
  compile 'org.datanucleus:datanucleus-core:5.0.3'
  compile 'org.datanucleus:datanucleus-api-jdo:5.0.3'
  compile 'org.datanucleus:datanucleus-rdbms:5.0.3'
  compile 'org.datanucleus:javax.jdo:3.2.0-m5'

  // DB
  compile 'com.h2database:h2:1.4.193'
}

Note that instead of relying on javax.jdo: jdo-api: * as the interface for JDO, we use ʻorg.datanucleus: javax.jdo: * `provided by DataNucleus. .. There seems to be no problem with earlier versions of DataNucleus, but it seems better to use the DataNucleus interface in 5.x.x series.

Also, of course, you need a DB connector. This time, we will adopt H2 for the database, so add the H2 driver to the dependency. If you just want to use the driver, you can use runtime, but this time I want to use the web console, so I specify compile.

Import the created Gradle file with Intellij IDEA. If you use Eclipse or don't need an IDE, please proceed in an appropriate way. (Throwing feeling) As an aside, Gradle is already v3.1 ... I noticed when I was looking at the lower right corner of IDEA.

JDO model

Next, I would like to create a model class for use with JDO. Here's an example, but I think it's helpful to look at other pages about JDO (especially the official App Engine documentation). The common ʻAuthor and Book` classes.

java/net/leak4mk0/test/datanucleus/Author.java


package net.leak4mk0.test.datanucleus;

import java.util.Set;
import javax.jdo.annotations.Element;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable //Class to persist
public class Author {
  @PrimaryKey //Primary key
  @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) //Automatically generate a unique key
  private Long id;

  @Persistent //Fields to persist
  private String name;

  @Persistent(mappedBy = "author")
  @Element(dependent = "true")
  private Set<Book> books;

  public Author(String name) {
    this.name = name;
  }

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

java/net/leak4mk0/test/datanucleus/Book.java


package net.leak4mk0.test.datanucleus;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable
public class Book {
  @PrimaryKey
  @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
  private Long id;

  @Persistent
  private Author author;

  @Persistent
  private String title;

  public Book(Author author, String title) {
    this.author = author;
    this.title = title;
  }

  public Author getAuthor() {
    return this.author;
  }

  public void setAuthor(Author author) {
    this.author = author;
  }

  public String getTitle() {
    return this.title;
  }

  public void setTitle(String title) {
    this.title = title;
  }
}

We will use annotations to specify how to persist.

JDO configuration file

Some settings are required for JDO to access the DB. We will set what to use for JDO implementation, DB connection destination, driver, user, etc. For details, refer to the following page. http://www.datanucleus.org/products/datanucleus/jdo/pmf.html

resources/META-INF/jdoconfig.xml


<?xml version="1.0" encoding="utf-8"?>
<jdoconfig xmlns="http://xmlns.jcp.org/xml/ns/jdo/jdoconfig">
  <persistence-manager-factory name="memory-h2">
    <property name="javax.jdo.PersistenceManagerFactoryClass"
        value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
    <property name="javax.jdo.option.ConnectionURL" value="jdbc:h2:mem:test"/>
    <property name="javax.jdo.option.ConnectionDriverName" value="org.h2.Driver"/>
    <property name="javax.jdo.option.ConnectionUserName" value="sa"/>
    <property name="javax.jdo.option.ConnectionPassword" value=""/>
    <property name="datanucleus.schema.autoCreateTable" value="true"/>
  </persistence-manager-factory>
</jdoconfig>

It is also possible to describe multiple settings, such as changing the DB used during development and operation. This can be done by writing multiple persistence-manager-factory elements with different name attributes.

Main code

And the main code. You probably won't use multibyte variable names in your actual code, but it might be useful when writing sample code. Code completion is hard to work, but ...

java/net/leak4mk0/test/datanucleus/Main.java


package net.leak4mk0.test.datanucleus;

import java.sql.SQLException;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import org.h2.tools.Server;

public class Main {
  public static void main(String[] args) throws SQLException {
    final PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("memory-h2");
    final PersistenceManager pm = pmf.getPersistenceManager();

final Author Ryunosuke Akutagawa= new Author("Ryunosuke Akutagawa");
final Author Fukuzawa Yukichi= new Author("Fukuzawa Yukichi");
final Author Osamu Dazai= new Author("Osamu Dazai");
    pm.makePersistentAll(Yukichi Fukuzawa,Osamu Dazai); //Persistence

final Book Rashomon= new Book(Ryunosuke Akutagawa, "Rashomon");
    pm.makePersistentAll(Rashomon); //Persistence

final Book Western affairs= new Book(Yukichi Fukuzawa, "Western affairs");
final Book Academic Recommendations= new Book(Yukichi Fukuzawa, "An Encouragement of Learning");
    pm.makePersistentAll(Western affairs,An Encouragement of Learning); //Persistence

final Book Hyakukei Tomitake= new Book(Osamu Dazai, "100 views of Tomitake");
final Book Run, Melos!= new Book(Osamu Dazai, "Run, Melos!");
final Book Tsugaru= new Book(Osamu Dazai, "Tsugaru");
    pm.makePersistentAll(100 views of Tomitake,Run, Melos!,Tsugaru); //Persistence

    pm.deletePersistentAll(Rashomon); //Delete

An Encouragement of Learning.author =Osamu Dazai; //Change

    Server.main(); //Launch console
  }
}

Basically, makePersistent to persist the data and deletePersistent to delete it. Also, if you want to change the data once persisted, just change the field. I haven't posted it this time, but when searching, I will use the newQuery and ʻexecuteList` methods.

One more step, Enhance

Finally, there is one job left. As you can see, using JDO to persist a model with very concise code, because DataNucleus adds the code you really need to each class. Adding code by referring to the annotation information is called Enhance, and Enhancer must enhance the model class after compilation in order to persist the model class. Details on how to operate Enhancer are described on the following page. http://www.datanucleus.org/products/datanucleus/jdo/enhancer.html

Writing this in Gradle is the main point of this article. (It was long…) I will write it quickly with reference to the description method in Ant.

build.gradle


//Omission...
task enhance {
  description = 'DataNucleus enhancement'
  dependsOn compileJava

  doLast {
    ant.taskdef(
            name: 'datanucleusenhancer',
            classpath: sourceSets.main.runtimeClasspath.asPath,
            classname: 'org.datanucleus.enhancer.EnhancerTask'
    )

    ant.datanucleusenhancer(
            classpath: sourceSets.main.runtimeClasspath.asPath,
            failonerror: true,
            verbose: true,
            api: 'JDO') {
      fileset(dir: sourceSets.main.output.classesDir)
    }
  }
}
classes.dependsOn enhance

Since it uses a class file, it must be executed after the compileJava task, and dependsOn specifies that it depends on compileJava. It also makes the classes task dependent on the ʻenhance` task to ensure that it is enhanced before execution.

Execution result

After that, gradlew run should start the browser and check the contents of the database. Make sure to specify jdbc: h2: mem: test in the JDBC URL.

image You can see that all the persistence processing done in the main code has been applied.

at the end

This time, the most important thing was how to enhance DataNucleus with Gradle. When actually operating on GCP, when adding dependencies to Gradle, there was a further fitting point due to library conflicts etc ... If there are obvious coding mistakes but exceptions, you may want to look at Gradle's dependency tree once.

Until the end Thank you for reading. Feel free to use the code shown in this article. However, please note that we cannot take any responsibility.

Recommended Posts

DataNucleus starting with Gradle
Use ProGuard with Gradle
Integration Test with Gradle
Install Gradle with ubuntu16.04
Starting with Swift Swift UI
CarPlay starting with iOS14
Use WebJars with Gradle
Get started with Gradle
Use jlink with gradle
Java multi-project creation with Gradle
Gradle + Kotlin-Generate jar with DSL
GraphQL Client starting with Ruby
Spring Boot starting with copy
Remote debugging with Gradle test
Spring Boot starting with Docker
Use log4j2 with YAML + Gradle
Hello World with SpringBoot / Gradle
Build a Java project with Gradle
Gradle
I tried using JOOQ with Gradle
Output test coverage with clover + gradle
Develop Processing with IntelliJ + Kotlin + Gradle
Spring Boot gradle build with Docker
A memorandum when starting new development with IntelliJ + Gradle + SpringBoot + JUnit5 (jupiter)
[Java] Create an executable module with Gradle
CICS-Run Java applications-(3) Build management with Gradle
Getting Started with Java Starting from 0 Part 1
AWS Lambda with Java starting now Part 1
Configure a multi-project with subdirectories in Gradle
JUnit 5 gradle test fails with lombok annotation
Java automated test implementation with JUnit 5 + Gradle
Download JDK with Gradle and make JRE
Add scripts to distributions created with gradle
(IntelliJ + gradle) Hello World with Spring Boot