HHH-6489 @Tempoeral support
This commit is contained in:
parent
3cbd2ae908
commit
605ce4ba29
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.binding;
|
package org.hibernate.metamodel.binding;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -36,7 +37,7 @@ public class HibernateTypeDescriptor {
|
||||||
private String explicitTypeName;
|
private String explicitTypeName;
|
||||||
private String javaTypeName;
|
private String javaTypeName;
|
||||||
private boolean isToOne;
|
private boolean isToOne;
|
||||||
private Map<String, String> typeParameters;
|
private Map<String, String> typeParameters = new HashMap<String, String>( );
|
||||||
|
|
||||||
private Type resolvedTypeMapping;
|
private Type resolvedTypeMapping;
|
||||||
|
|
||||||
|
|
|
@ -23,16 +23,23 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.source.annotations.attribute;
|
package org.hibernate.metamodel.source.annotations.attribute;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
import org.jboss.jandex.AnnotationInstance;
|
import org.jboss.jandex.AnnotationInstance;
|
||||||
import org.jboss.jandex.AnnotationValue;
|
import org.jboss.jandex.AnnotationValue;
|
||||||
import org.jboss.jandex.DotName;
|
import org.jboss.jandex.DotName;
|
||||||
|
|
||||||
|
import org.hibernate.AnnotationException;
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
|
import org.hibernate.cfg.NotYetImplementedException;
|
||||||
import org.hibernate.metamodel.source.annotations.AnnotationBindingContext;
|
import org.hibernate.metamodel.source.annotations.AnnotationBindingContext;
|
||||||
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
|
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
|
||||||
|
import org.hibernate.metamodel.source.annotations.JPADotNames;
|
||||||
import org.hibernate.metamodel.source.annotations.JandexHelper;
|
import org.hibernate.metamodel.source.annotations.JandexHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,6 +79,9 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
|
||||||
*/
|
*/
|
||||||
private final Map<String, String> explicitHibernateTypeParameters;
|
private final Map<String, String> explicitHibernateTypeParameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The binding context
|
||||||
|
*/
|
||||||
private final AnnotationBindingContext context;
|
private final AnnotationBindingContext context;
|
||||||
|
|
||||||
MappedAttribute(String name, Class<?> attributeType, String accessType, Map<DotName, List<AnnotationInstance>> annotations, AnnotationBindingContext context) {
|
MappedAttribute(String name, Class<?> attributeType, String accessType, Map<DotName, List<AnnotationInstance>> annotations, AnnotationBindingContext context) {
|
||||||
|
@ -80,34 +90,8 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.attributeType = attributeType;
|
this.attributeType = attributeType;
|
||||||
this.accessType = accessType;
|
this.accessType = accessType;
|
||||||
|
|
||||||
final AnnotationInstance typeAnnotation = JandexHelper.getSingleAnnotation(
|
|
||||||
annotations(),
|
|
||||||
HibernateDotNames.TYPE
|
|
||||||
);
|
|
||||||
if ( typeAnnotation != null ) {
|
|
||||||
this.explicitHibernateTypeName = typeAnnotation.value( "type" ).asString();
|
|
||||||
this.explicitHibernateTypeParameters = extractTypeParameters( typeAnnotation );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.explicitHibernateTypeName = null;
|
|
||||||
this.explicitHibernateTypeParameters = new HashMap<String, String>();
|
this.explicitHibernateTypeParameters = new HashMap<String, String>();
|
||||||
}
|
this.explicitHibernateTypeName = determineExplicitHibernateTypeName();
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> extractTypeParameters(AnnotationInstance typeAnnotation) {
|
|
||||||
HashMap<String, String> typeParameters = new HashMap<String, String>();
|
|
||||||
AnnotationValue parameterAnnotationValue = typeAnnotation.value( "parameters" );
|
|
||||||
if ( parameterAnnotationValue != null ) {
|
|
||||||
AnnotationInstance[] parameterAnnotations = parameterAnnotationValue.asNestedArray();
|
|
||||||
for ( AnnotationInstance parameterAnnotationInstance : parameterAnnotations ) {
|
|
||||||
typeParameters.put(
|
|
||||||
parameterAnnotationInstance.value( "name" ).asString(),
|
|
||||||
parameterAnnotationInstance.value( "value" ).asString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return typeParameters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -151,6 +135,86 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
|
||||||
sb.append( '}' );
|
sb.append( '}' );
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getTemporalType() {
|
||||||
|
final AnnotationInstance temporalAnnotation = JandexHelper.getSingleAnnotation(
|
||||||
|
annotations(),
|
||||||
|
JPADotNames.TEMPORAL
|
||||||
|
);
|
||||||
|
if ( isTemporalType( attributeType ) ) {
|
||||||
|
if ( temporalAnnotation == null ) {
|
||||||
|
//SPEC 11.1.47 The Temporal annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar.
|
||||||
|
throw new AnnotationException( "Attribute " + name + " is a Temporal type, but no @Temporal annotation found." );
|
||||||
|
}
|
||||||
|
TemporalType temporalType = JandexHelper.getEnumValue( temporalAnnotation, "value", TemporalType.class );
|
||||||
|
boolean isDate = Date.class.isAssignableFrom( attributeType );
|
||||||
|
String type = null;
|
||||||
|
switch ( temporalType ) {
|
||||||
|
case DATE:
|
||||||
|
type = isDate ? "date" : "calendar_date";
|
||||||
|
break;
|
||||||
|
case TIME:
|
||||||
|
type = "time";
|
||||||
|
if ( !isDate ) {
|
||||||
|
throw new NotYetImplementedException( "Calendar cannot persist TIME only" );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIMESTAMP:
|
||||||
|
type = isDate ? "timestamp" : "calendar";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new AssertionFailure( "Unknown temporal type: " + temporalType );
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( temporalAnnotation != null ) {
|
||||||
|
throw new AnnotationException(
|
||||||
|
"@Temporal should only be set on a java.util.Date or java.util.Calendar property: " + name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTemporalType(Class type) {
|
||||||
|
return Date.class.isAssignableFrom( type ) || Calendar.class.isAssignableFrom( type );
|
||||||
|
//todo (stliu) java.sql.Date is not listed in spec
|
||||||
|
// || java.sql.Date.class.isAssignableFrom( type )
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> extractTypeParameters(AnnotationInstance typeAnnotation) {
|
||||||
|
HashMap<String, String> typeParameters = new HashMap<String, String>();
|
||||||
|
AnnotationValue parameterAnnotationValue = typeAnnotation.value( "parameters" );
|
||||||
|
if ( parameterAnnotationValue != null ) {
|
||||||
|
AnnotationInstance[] parameterAnnotations = parameterAnnotationValue.asNestedArray();
|
||||||
|
for ( AnnotationInstance parameterAnnotationInstance : parameterAnnotations ) {
|
||||||
|
typeParameters.put(
|
||||||
|
parameterAnnotationInstance.value( "name" ).asString(),
|
||||||
|
parameterAnnotationInstance.value( "value" ).asString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String determineExplicitHibernateTypeName() {
|
||||||
|
String typeName = null;
|
||||||
|
String temporalType = getTemporalType();
|
||||||
|
final AnnotationInstance typeAnnotation = JandexHelper.getSingleAnnotation(
|
||||||
|
annotations(),
|
||||||
|
HibernateDotNames.TYPE
|
||||||
|
);
|
||||||
|
if ( typeAnnotation != null ) {
|
||||||
|
typeName = typeAnnotation.value( "type" ).asString();
|
||||||
|
this.explicitHibernateTypeParameters.putAll( extractTypeParameters( typeAnnotation ) );
|
||||||
|
}
|
||||||
|
else if ( temporalType != null ) {
|
||||||
|
typeName = temporalType;
|
||||||
|
|
||||||
|
}
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.hibernate.EntityMode;
|
||||||
import org.hibernate.cfg.NotYetImplementedException;
|
import org.hibernate.cfg.NotYetImplementedException;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.beans.BeanInfoHelper;
|
import org.hibernate.internal.util.beans.BeanInfoHelper;
|
||||||
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.metamodel.binding.AbstractPluralAttributeBinding;
|
import org.hibernate.metamodel.binding.AbstractPluralAttributeBinding;
|
||||||
import org.hibernate.metamodel.binding.AttributeBinding;
|
import org.hibernate.metamodel.binding.AttributeBinding;
|
||||||
import org.hibernate.metamodel.binding.CollectionElementNature;
|
import org.hibernate.metamodel.binding.CollectionElementNature;
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package org.hibernate.metamodel.source.annotations.entity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.AnnotationException;
|
||||||
|
import org.hibernate.metamodel.binding.AttributeBinding;
|
||||||
|
import org.hibernate.metamodel.binding.EntityBinding;
|
||||||
|
import org.hibernate.metamodel.binding.HibernateTypeDescriptor;
|
||||||
|
import org.hibernate.type.TimestampType;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Strong Liu
|
||||||
|
*/
|
||||||
|
public class TemporalBindingTests extends BaseAnnotationBindingTestCase {
|
||||||
|
@Entity
|
||||||
|
class Item1 {
|
||||||
|
@Id
|
||||||
|
long id;
|
||||||
|
Date date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = AnnotationException.class)
|
||||||
|
@Resources(annotatedClasses = TemporalBindingTests.Item1.class)
|
||||||
|
public void testNoTemporalAnnotationOnTemporalTypeAttribute() {
|
||||||
|
getEntityBinding( Item1.class );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class Item2 {
|
||||||
|
@Id
|
||||||
|
long id;
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
Date date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Resources(annotatedClasses = TemporalBindingTests.Item2.class)
|
||||||
|
public void testTemporalTypeAttribute() {
|
||||||
|
EntityBinding binding = getEntityBinding( Item2.class );
|
||||||
|
AttributeBinding attributeBinding = binding.getAttributeBinding( "date" );
|
||||||
|
HibernateTypeDescriptor descriptor = attributeBinding.getHibernateTypeDescriptor();
|
||||||
|
assertEquals( "timestamp", descriptor.getExplicitTypeName() );
|
||||||
|
assertEquals( Date.class.getName(), descriptor.getJavaTypeName() );
|
||||||
|
assertNotNull( descriptor.getResolvedTypeMapping() );
|
||||||
|
assertEquals( TimestampType.class, descriptor.getResolvedTypeMapping().getClass() );
|
||||||
|
assertNotNull( descriptor.getTypeParameters() );
|
||||||
|
assertTrue( descriptor.getTypeParameters().isEmpty() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class Item3 {
|
||||||
|
@Id
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
Date date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Resources(annotatedClasses = TemporalBindingTests.Item3.class)
|
||||||
|
public void testTemporalTypeAsId() {
|
||||||
|
EntityBinding binding = getEntityBinding( Item3.class );
|
||||||
|
AttributeBinding attributeBinding = binding.getAttributeBinding( "date" );
|
||||||
|
HibernateTypeDescriptor descriptor = attributeBinding.getHibernateTypeDescriptor();
|
||||||
|
assertEquals( "timestamp", descriptor.getExplicitTypeName() );
|
||||||
|
assertEquals( Date.class.getName(), descriptor.getJavaTypeName() );
|
||||||
|
assertNotNull( descriptor.getResolvedTypeMapping() );
|
||||||
|
assertEquals( TimestampType.class, descriptor.getResolvedTypeMapping().getClass() );
|
||||||
|
assertNotNull( descriptor.getTypeParameters() );
|
||||||
|
assertTrue( descriptor.getTypeParameters().isEmpty() );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue