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.
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.
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.
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.
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.
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.
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.
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.
You can see that all the persistence processing done in the main code has been applied.
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