HHH-6489 @Tempoeral support

This commit is contained in:
Hardy Ferentschik 2011-07-27 14:08:34 +02:00
parent 3cbd2ae908
commit 605ce4ba29
4 changed files with 177 additions and 30 deletions

View File

@ -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;

View File

@ -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;
}
} }

View File

@ -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;

View File

@ -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() );
}
}