@Repeatable annotations for JDO and JPA

DataNucleus now provides access to Java8 @Repeatable annotations for use with JDO and JPA. Previously, if you wanted to specify, for example, multiple indexes for a class using annotations, you would have to do it like this (for JDO) using a container annotation

@Indices({
    @Index(name="MYINDEX_1", members={"field1","field2"}), 
    @Index(name="MYINDEX_2", members={"field3"})})
public class Person
{
    ...
}

The JDO 3.2 annotations have now been upgraded (in javax.jdo v3.2.0-m6) to support the Java8 @Repeatable setting meaning that you can now do

@Index(name="MYINDEX_1", members={"field1","field2"})
@Index(name="MYINDEX_2", members={"field3"})
public class Person
{
    ...
}

The same applies to all standard JDO annotations that have a container annotation.

 

For JPA, the same is also now true (though clearly since Oracle seemingly doesn’t care one iota about pushing the JPA spec forward then this is not in the official JPA spec yet). However since DataNucleus provides its own “standard” javax.persistence jar , we have now published version v2.2.0-m1 of this jar adding support for @Repeatable just like with the JDO 3.2 annotations. So any annotation that has container annotation can now be repeated on a class/field/method, you just have to use v2.2.0-m1 of the DataNucleus javax.persistence jar. For example

@Entity
@NamedNativeQuery(name="AllPeople", 
    query="SELECT * FROM PERSON WHERE SURNAME = 'Smith'")
@NamedNativeQuery(name="PeopleCalledJones",
    query="SELECT * FROM PERSON WHERE SURNAME = 'Jones')
public class Person
{
    ...
}

 

Posted in Uncategorized | Leave a comment

DN v5 : Multi-tenancy improvements

JDO and JPA APIs don’t define any support for multi-tenancy, other than where you want to have 1 PMF/EMF per tenant and they have their own database or schema. DataNucleus introduced support for multi-tenancy using the same schema back in v4, whereby the tables that are shared will have an extra discriminator column which specifies the tenant the row applies to, and you specify a persistence property datanucleus.tenantId for the PMF/EMF you are using, defining the tenant it is for. This is fine as far as it goes, but requires that each tenant have their own PMF/EMF. DataNucleus v5 makes this more flexible.

The first change is that you can now specify that same persistence property on the PM/EM (pm.setProperty(…), em.setProperty(…)), so you can now potentially have a PM/EM for each tenant, and the data is separated that way via the tenancy discriminator as in v4. The use-case for this is where you have a web based system and each request has a user, so you create a PM/EM, set the tenant id based on the user, and then each database access will use the appropriate tenant.

PersistenceManage pm1 = pmf.getPersistenceManager();
pm1.setProperty("datanucleus.tenantId", "John");
... // All operations under tenant "John"
pm1.close();

PersistenceManager pm2 = pmf.getPersistenceManager();
pm2.setProperty("datanucleus.tenantId", "Gary");
... // All operations under tenant "Gary"
pm2.close();

The second change is that you can optionally also specify a MultiTenancyProvider, implementing this interface

public interface MultiTenancyProvider
{
     String getTenantId(ExecutionContext ec);
}

and specify the persistence property datanucleus.tenantProvider to point to an instance of your MultiTenancyProvider class. This means that, for example, if you have some session variable that identifies the user and want to share the PM/EM across your users, then you can use this provider instance to define the tenant id for each call. This feature is likely going to be much less useful than the different tenant per PM/EM but it is there for your convenience.

Posted in Uncategorized | Leave a comment

DN v5 : Improved support for Enum persistence

With standard JDO and JPA you can persist a Java enum field as either the name (String-based column) or the ordinal (Number-based column). This is great as far as it goes, so we can easily persist fields using this enum.

public enum Colour{RED, GREEN, BLUE;}

In some situations however you want to configure what is stored. Say, we want to store a numeric value for each enum constant but not the default values (for some reason). In DataNucleus up to and including v4 (for RDBMS only!) we allowed persistence of

public enum Colour
{
    RED(1), 
    GREEN(3), 
    BLUE(5);

    int code;
    private Colour(short val) {this.code = val;}
    public short getCode() {return this.code;}
    public static Colour getEnumByCode(short val)
    {
        case 1: return RED;
        case 3: return GREEN;
        case 5: return BLUE;
    }
}

and then you set metadata for each enum field of this type to specify that you want to persist the “code” value, like this

@Extensions({
    @Extension(vendorName="datanucleus", key="enum-getter-by-value", value="getEnumByCode"),
    @Extension(vendorName="datanucleus", key="enum-value-getter", value="getCode")
   })
Colour colour;

This was fine, except required too much of the user.

 

DataNucleus v5 simplifies it, and you can now do

public enum Colour
{
    RED(1), 
    GREEN(3), 
    BLUE(5);

    int code;
    private Colour(short val) {this.code = val;}
    public short getCode() {return this.code;}
}

and mark each enum field like this

@Extension(vendorName="datanucleus", key="enum-value-getter", value="getCode")
Colour colour;

We don’t stop there however, because the value that is persisted using this extended method can now be either short, int or String. It is also now available for use on RDBMS, Cassandra, MongoDB, HBase, Neo4j, ODF, Excel, and JSON, so your code is more portable too!

Posted in Uncategorized | Leave a comment

DN v5 : Support for Java8 “Optional”

Java 8 introduces a class (java.util.Optional) that represents either a value or null. DataNucleus v5 has a requirement of Java 8, and adds support for persisting and querying fields of this type. Let’s suppose we have a class like this

public class MyClass
{
    private Optional<String> description;
    ...
}

By default DataNucleus will persist this as if it was of the generic type of the Optional (String in this example). Consequently on an RDBMS we will have a column in the datastore of type VARCHAR(255) NULL. If the field description represents a null then it will be persisted as NULL, otherwise as the value contained in the Optional. It supports the generic type being a normal basic type (though not a collection, map, array), or a persistable object.

JDOQL in JDO 3.2 adds support for querying the Optional field, like this

Query q = pm.newQuery(
    "SELECT FROM mydomain.MyClass WHERE description.isPresent()");

So this will return all instances of the class where the description field represents a value. Similarly we can return the value represented by the Optional field, like this

Query q = pm.newQuery(
    "SELECT description.get() FROM mydomain.MyClass");

As you can see, JDOQL makes use of standard Java method namings for accessing the Optional field.

For JPA querying, you can simply refer to the Optional field as if it was of the generic type represented.

This is part of the JDO3.2 spec and you can make use of it in DataNucleus v5+. It is not currently part of the JPA2.1 spec, but you still can make use of it in DataNucleus v5+ when using JPA.

Posted in Uncategorized | Leave a comment

DN v5 : JPA with “nondurable” identity

With standard JPA you only have the ability to have “application” identity for an entity (i.e field(s) marked as being part of the primary-key). Some time ago we added vendor extension support for having a surrogate (datastore) identity for an entity with DataNucleus. DataNucleus v5 now adds a further vendor extension whereby you can have an entity that has no identity. This is useful where you maybe have a class that represents a log entry and you don’t have need to access a specific object (other than searching for all entries with particular field value(s)). You would do this as follows

@Entity
@org.datanucleus.api.jpa.annotations.NonDurableId
public class LogEntry
{
    String level;
    String category;
    String message;

    ...
}

Note that you can specify this in orm.xml also, see the DataNucleus documentation. So we have made use of a DataNucleus-specific annotation, and now we can persist objects of this type and they will not be assigned an identity. We now handle objects of this type in the normal way for querying, just that we cannot use em.find(…).

This is not part of the JPA 2.1 spec, and is not likely to be included in a JPA spec any time soon, but you can make use of it in DataNucleus v5+.

Posted in Uncategorized | Leave a comment

DN v5 : JPQL FROM JOIN to another “root” entity

A vendor extension now available in DataNucleus v5 is for JPQL’s ability to JOIN to other entities. In standard JPQL you can only add a JOIN through a relation. For example

SELECT p FROM Person p 
    JOIN p.address a WHERE a.street = 'Main Street'

In this example we have a candidate “root” entity of Person, and are joining to the Address entity via the “address” relation field in Person.

The vendor extension provides the ability to join to a new “root” entity. For example

SELECT p FROM Person p 
    LEFT OUTER JOIN Address a ON p.addressName = a.name

In this example we have a candidate “root” entity of Person, and we are joining to the Address entity using a manually specified ON clause. That is, there doesn’t need to be a relation between Person and Address to make this join, just a condition that we are imposing in the ON clause.

This is not part of the JPA 2.1 spec, but may be in a future JPA spec, but you can make use of it in DataNucleus v5+.

Posted in Uncategorized | Leave a comment

JDO 3.2 JDOQLTypedQuery : improvements relative to DN extension

Now that JDO 3.2 standardises the “typed query” mechanism that we prototyped in DataNucleus v3.x and v4.0/v4.1 it is worth mentioning the additions to the API that are present in the JDO 3.2 variant.

StringExpression

This has gained the following methods to providing JDOQL “matches” operation capability

BooleanExpression matches(StringExpression expr);
BooleanExpression matches(String str);

 

NumericExpression

The following methods are added, for bitwise operations support

NumericExpression bAnd(NumericExpression bitExpr);
NumericExpression bOr(NumericExpression bitExpr);
NumericExpression bXor(NumericExpression bitExpr);

In addition it also gains these methods to match the equivalent JDOQL string based operators (-, ~)

NumericExpression neg();
NumericExpression com();

 

CharacterExpression

This also gains the JDOQL string based operators (-, ~)

NumericExpression neg();
NumericExpression com();

 

BooleanExpression

This gains the JDOQL string based operator (-)

BooleanExpression neg();

Java 8

In addition to the above you can now also make use of Java8 Time types in JDOQLTypedQuery, whereas this was not possible in the previous DataNucleus extension.

 

API

The JDOQLTypedQuery class has some slight changes to make it more consistent with the JDOQL standard API.

  • Added method result(…) rather than specifying result clauses in the execute call.
  • Changed addExtension/setExtensions methods to extension(…)/extensions(…).
  • Added unmodifiable, serializeRead, datastoreReadTimeout, datastoreWriteTimeout, ignoreCache, saveAsNamedQuery.
Posted in JDO, JDOQL, LINQ, Uncategorized | Leave a comment