Appliweb

All dimensions of your web developments

Affichage des articles marqués datanucleus

I’ve been trying Google app. engine in my spare time.

I maintain a small library (RER) and make an html designer tool for Java (Appliweb), so I tried to make it work under GAE.

I know GAE supports persistence with JPA, using the datanucleus library.

But only basic stuff is supported, and you can easily forget about the rest. For example, I knew that many to many relationships did not work, that inheritance is hard to make it eventually work (that’s why I added ValueObject supports in RER library), but many times I encounter strong limitations, and I think this last one will make me rethink on GAE supports:

Let me explain, I have the following classes and mapping.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Entity(name="Article")
@Table(name="ARTICLE")
public class ArticleImpl implements Article {
@Id
@GeneratedValue
protected Long id;

@Basic
@Column(length=3000)
protected String content;

@ManyToOne(optional=false)
protected Writer writer;

@ManyToOne(optional=false)
@Column(name="BLOG")
protected Blog blog;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Entity(name="Blog")
@Table(name="BLOG")
public class BlogImpl implements Blog
{

@Id
@GeneratedValue
protected Long id;

@Basic
@Column(length=256)
protected String rootUrl;

@ManyToOne(optional=false)
protected User owner;

@OneToMany(targetEntity=ArticleImpl.class)
protected Set<? extends Article> articles=new HashSet<ArticleImpl>();
}

See the OneToMany relationship between ArticleImpl and BlogImpl ? It’s quite standard isn’t it ?

But that fails completely in GAE, with the following error message:

1
2
3
javax.persistence.PersistenceException: Error in meta-data for net.appliweb.rera.test.jpa.model.ArticleImpl.id: Cannot have a java.lang.Long primary key and be a child object (owning field is net.appliweb.rera.test.jpa.model.BlogImpl.articles).

at org.datanucleus.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:264)

To my point of view, it’s clearly not understandable why Long primary keys are not supported. I don’t want to switch to Integer, not because a blog can have more than 4 billions articles, but because the application can have millions of blogs with millions of articles (who knows ?), and I always put Long for the Id of an entity.

It seems ArticleImpl is considered a child of BlogImpl, and it cannot have it’s own life (and Long Id) outside of BlogImpl. That’s clearly not what I want.

Conclusion:
Don’t try to use JPA for GAE persistence, because the design of a RDBMS and GAE are too different, and you will always have problems like this.

2nd conclusion:
I’m back in trying to find another solution. Supporting both RDBMS and GAE would be nice.

As Google App. Engine uses a datanucleus plugin for database access, I’ve now switched to it (and leaved Hibernate).

Datanucleus uses bytecode instrumentation for persistance mapping, but not in real time like Hibernate does. Your classes must be enhanced just after compilation.

With maven, it’s not a problem for me, as described here:
http://www.datanucleus.org

Netbeans + Linux + Maven + datanucleus-plugin = hell

Using datanucleus-maven-plugin 1.1.4 (don’t use version 1.1.3 it will force download of Datanucleus 2.0), I get an error when running the compilation under Netbeans.

1.
2.
Embedded error: Error while executing process.
java.io.IOException: error=2, No such file or directory.

I then enable the log for the plugin to see what’s happening, but get no logs. No logs at all…

Of course, nothing in the doc about this problem, so I finally searched the plugin source code:

I see that the plugin is calling « java » directly to process the enhancements. And it seems that when Netbeans calls Maven for compilation, it doesn’t provide the linux path, so the plugin couldn’t start java.

I noticed then a hidden or not-so-documented option, fork, that if set to false, will call directly the bytecode enhancer with no calls to « java ».
Here is the maven configuration to use:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
<plugin>
  <groupId>org.datanucleus</groupId>
  <artifactId>maven-datanucleus-plugin</artifactId>
  <version>1.1.4</version>
  <configuration>
    <fork>false</fork>
    <mappingIncludes>**/*.class</mappingIncludes>
    <api>JPA</api>
    <log4jConfiguration>
      ${basedir}/src/test/resources/log4j.properties
    </log4jConfiguration>
    <verbose>true</verbose>
    <enhancerName>ASM</enhancerName>
    <props>
       ${project.build.testOutputDirectory}/datanucleus.properties
    </props>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derbyclient</artifactId>
      <version>10.5.3.0_1</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
    </dependency>
  </dependencies>
</plugin>

So I tried, and this worked like a charm.
PS: The other plugin, schema-create doesn’t have this option, so I have to run it from command line.