When persisting a class, a persistence solution needs to know how to persist the types of each field in the class. Clearly a persistence solution can only support a finite number of Java types; it cannot know how to persist every possible type creatable. The JPA specification define lists of types that are required to be supported by all implementations of those specifications. This support can be conveniently split into two parts
An object that can be referred to (object reference, providing a relation) and that has an "identity" is termed a primary type. DataNucleus supports the following Java types as primary
An object that does not have an "identity" is termed a secondary type. This is something like a String or Date field in a class, or alternatively a Collection (that contains other objects), or an embedded Entity. The table below shows the currently supported secondary java types in DataNucleus. The table shows
Java Type | Extension? | EAGER? | Persistent? | Proxied? | PK? | Plugin |
---|---|---|---|---|---|---|
boolean | datanucleus-core | |||||
byte | datanucleus-core | |||||
char | datanucleus-core | |||||
double | datanucleus-core | |||||
float | datanucleus-core | |||||
int | datanucleus-core | |||||
long | datanucleus-core | |||||
short | datanucleus-core | |||||
boolean[] | datanucleus-core | |||||
byte[] | datanucleus-core | |||||
char[] | datanucleus-core | |||||
double[] | datanucleus-core | |||||
float[] | datanucleus-core | |||||
int[] | datanucleus-core | |||||
long[] | datanucleus-core | |||||
short[] | datanucleus-core | |||||
java.lang.Boolean | datanucleus-core | |||||
java.lang.Byte | datanucleus-core | |||||
java.lang.Character | datanucleus-core | |||||
java.lang.Double | datanucleus-core | |||||
java.lang.Float | datanucleus-core | |||||
java.lang.Integer | datanucleus-core | |||||
java.lang.Long | datanucleus-core | |||||
java.lang.Short | datanucleus-core | |||||
java.lang.Boolean[] | datanucleus-core | |||||
java.lang.Byte[] | datanucleus-core | |||||
java.lang.Character[] | datanucleus-core | |||||
java.lang.Double[] | datanucleus-core | |||||
java.lang.Float[] | datanucleus-core | |||||
java.lang.Integer[] | datanucleus-core | |||||
java.lang.Long[] | datanucleus-core | |||||
java.lang.Short[] | datanucleus-core | |||||
java.lang.Number [2] | datanucleus-core | |||||
java.lang.Object | datanucleus-core | |||||
java.lang.String | datanucleus-core | |||||
java.lang.StringBuffer [1] | datanucleus-core | |||||
java.lang.String[] | datanucleus-core | |||||
java.lang.Class | datanucleus-core | |||||
java.math.BigDecimal | datanucleus-core | |||||
java.math.BigInteger | datanucleus-core | |||||
java.math.BigDecimal[] | datanucleus-core | |||||
java.math.BigInteger[] | datanucleus-core | |||||
java.sql.Date | datanucleus-core | |||||
java.sql.Time | datanucleus-core | |||||
java.sql.Timestamp | datanucleus-core | |||||
java.util.ArrayList | datanucleus-core | |||||
java.util.BitSet | datanucleus-core | |||||
java.util.Calendar [5] | datanucleus-core | |||||
java.util.Collection | datanucleus-core | |||||
java.util.Currency | datanucleus-core | |||||
java.util.Date | datanucleus-core | |||||
java.util.Date[] | datanucleus-core | |||||
java.util.GregorianCalendar [5] | datanucleus-core | |||||
java.util.HashMap | datanucleus-core | |||||
java.util.HashSet | datanucleus-core | |||||
java.util.Hashtable | datanucleus-core | |||||
java.util.LinkedHashMap [3] | datanucleus-core | |||||
java.util.LinkedHashSet [4] | datanucleus-core | |||||
java.util.LinkedList | datanucleus-core | |||||
java.util.List | datanucleus-core | |||||
java.util.Locale | datanucleus-core | |||||
java.util.Locale[] | datanucleus-core | |||||
java.util.Map | datanucleus-core | |||||
java.util.Properties | datanucleus-core | |||||
java.util.PriorityQueue | datanucleus-core | |||||
java.util.Queue | datanucleus-core | |||||
java.util.Set | datanucleus-core | |||||
java.util.SortedMap | datanucleus-core | |||||
java.util.SortedSet | datanucleus-core | |||||
java.util.Stack | datanucleus-core | |||||
java.util.TimeZone | datanucleus-core | |||||
java.util.TreeMap | datanucleus-core | |||||
java.util.TreeSet | datanucleus-core | |||||
java.util.UUID | datanucleus-core | |||||
java.util.Vector | datanucleus-core | |||||
java.awt.Color | datanucleus-core | |||||
java.awt.image.BufferedImage | datanucleus-core | |||||
java.awt.Point | datanucleus-geospatial | |||||
java.awt.Rectangle | datanucleus-geospatial | |||||
java.net.URI | datanucleus-core | |||||
java.net.URL | datanucleus-core | |||||
java.io.Serializable | datanucleus-core | |||||
java.io.File [6] | datanucleus-rdbms | |||||
persistable | datanucleus-core | |||||
persistable[] | datanucleus-core | |||||
java.lang.Enum | datanucleus-core | |||||
java.lang.Enum[] | datanucleus-core | |||||
java.time.LocalDateTime | datanucleus-java8 | |||||
java.time.LocalTime | datanucleus-java8 | |||||
java.time.LocalDate | datanucleus-java8 | |||||
java.time.MonthDay | datanucleus-java8 | |||||
java.time.YearMonth | datanucleus-java8 | |||||
java.time.Year | datanucleus-java8 | |||||
java.time.Period | datanucleus-java8 | |||||
java.time.Instant | datanucleus-java8 | |||||
java.time.Duration | datanucleus-java8 | |||||
java.time.ZoneId | datanucleus-java8 | |||||
java.time.ZoneOffset | datanucleus-java8 | |||||
org.joda.time.DateTime | datanucleus-jodatime | |||||
org.joda.time.LocalTime | datanucleus-jodatime | |||||
org.joda.time.LocalDate | datanucleus-jodatime | |||||
org.joda.time.LocalDateTime | datanucleus-jodatime | |||||
org.joda.time.Duration | datanucleus-jodatime | |||||
org.joda.time.Interval | datanucleus-jodatime | |||||
org.joda.time.Period | datanucleus-jodatime | |||||
com.google.common.collect.Multiset | datanucleus-guava |
Note that support is available for persisting other types depending on the datastore to which you are persisting
If you have support for any additional types and would either like to contribute them, or have them listed here, let us know
You can add support for other basic Java types quite easily, particularly if you can store it as a String or Long and then retrieve it back into its object form from that - See the Java Types plugin-point You can also define more specific support for it with RDBMS datastores - See the RDBMS Java Types plugin-point
SortedSet (and implementations) allow the user to have a comparator to order the elements of the set. When an object is pulled back from the datastore via query JPA would need to know the class name of the comparator to use. You specify it like this
@OneToMany @Extension(vendorName="datanucleus", key="comparator-name", value="mydomain.model.MyComparator") SortedSet<MyElementType> elements;
and when instantiating the SortedSet field will create it with a comparator of the specified class (which must have a default constructor). Same for Queue, PriorityQueue and SortedMap.
JPA2.1 introduces an API for conversion of an attribute of an Entity to its datastore value. You can define a "converter" that will convert to the datastore value and back from it, implementing this interface.
public interface AttributeConverter<X,Y> { public Y convertToDatabaseColumn (X attributeObject); public X convertToEntityAttribute (Y dbData); }
so if we have a simple converter to allow us to persist fields of type URL in a String form in the datastore, like this
public class URLStringConverter implements AttributeConverter<URL, String> { public URL convertToEntityAttribute(String str) { if (str == null) { return null; } URL url = null; try { url = new java.net.URL(str.trim()); } catch (MalformedURLException mue) { throw new IllegalStateException("Error converting the URL", mue); } return url; } public String convertToDatabaseColumn(URL url) { return url != null ? url.toString() : null; } }
and now in our Entity class we mark any URL field as being converted using this converter
@Entity public class MyClass { @Id long id; @Basic @Convert(converter=URLStringConverter.class) URL url; ... }
Note that in strict JPA 2.1 you have to mark all converters with the @Converter annotation. In DataNucleus if you specify the converter class name in the @Convert then we know its a converter so don't really see why we need a user to annotate the converter too. We only require annotation as @Converter if you want the converter to always be applied to fields of a particular type. i.e if you want all URL fields to be persisted using the above converter (without needing to put @Convert on each field of that type) then you would add the annotation
@Converter(autoApply=true) public class URLStringConverter implements AttributeConverter<URL, String> { ... }
Note that if you have some java type with a @Converter registered to "autoApply", you can turn it off on a field-by-field basis with
@Convert(disableConversion=true) URL url;
A further use of AttributeConverter is where you want to apply type conversion to the key/value of a Map field, or to the element of a Collection field. The Collection element case is simple, you just specify the @Convert against the field and it will be applied to the element. If you want to apply type conversion to a key/value of a map do this.
@Convert(attributeName="key", converter=URLStringConverter.class) Map<URL, OtherEntity> myMap;
So we specify the attributeName to be key, and to use it on the value we would set it to value.
By default an Enum is persisted as either a String form (the name), or as an integer form (the ordinal). You control which form by specifying the @Enumerated annotation (or equivalent XML).
An extension to this for RDBMS is where you have an Enum that defines its own "value"s for the different enum options.
public enum MyColour { RED((short)1), GREEN((short)3), BLUE((short)5), YELLOW((short)8); private short value; private MyColour(short value) { this.value = value; } public short getValue() { return value; } public static MyColour getEnumByValue(short value) { switch (value) { case 1: return RED; case 3: return GREEN; case 5: return BLUE; default: return YELLOW; } } }
With the default persistence it would persist as String-based, so persisting "RED" "GREEN" "BLUE" etc. With jdbc-type as INTEGER it would persist 0, 1, 2, 3 being the ordinal values. If you define the metadata as
@Extensions({ @Extension(vendorName="datanucleus", key="enum-getter-by-value", value="getEnumByValue"), @Extension(vendorName="datanucleus", key="enum-value-getter", value="getValue") }) MyColour colour;
this will now persist 1, 3, 5, 8, being the "value" of each of the enum options.
You could try to persist Eclipse EMF models using the Texo project to generate POJOs