Skip to content

Commit 605ce4b

Browse files
committed
HHH-6489 @Tempoeral support
1 parent 3cbd2ae commit 605ce4b

File tree

4 files changed

+177
-30
lines changed

4 files changed

+177
-30
lines changed

hibernate-core/src/main/java/org/hibernate/metamodel/binding/HibernateTypeDescriptor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424
package org.hibernate.metamodel.binding;
2525

26+
import java.util.HashMap;
2627
import java.util.Map;
2728

2829
import org.hibernate.type.Type;
@@ -36,7 +37,7 @@ public class HibernateTypeDescriptor {
3637
private String explicitTypeName;
3738
private String javaTypeName;
3839
private boolean isToOne;
39-
private Map<String, String> typeParameters;
40+
private Map<String, String> typeParameters = new HashMap<String, String>( );
4041

4142
private Type resolvedTypeMapping;
4243

hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/attribute/MappedAttribute.java

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,23 @@
2323
*/
2424
package org.hibernate.metamodel.source.annotations.attribute;
2525

26+
import java.util.Calendar;
27+
import java.util.Date;
2628
import java.util.HashMap;
2729
import java.util.List;
2830
import java.util.Map;
31+
import javax.persistence.TemporalType;
2932

3033
import org.jboss.jandex.AnnotationInstance;
3134
import org.jboss.jandex.AnnotationValue;
3235
import org.jboss.jandex.DotName;
3336

37+
import org.hibernate.AnnotationException;
38+
import org.hibernate.AssertionFailure;
39+
import org.hibernate.cfg.NotYetImplementedException;
3440
import org.hibernate.metamodel.source.annotations.AnnotationBindingContext;
3541
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
42+
import org.hibernate.metamodel.source.annotations.JPADotNames;
3643
import org.hibernate.metamodel.source.annotations.JandexHelper;
3744

3845
/**
@@ -72,6 +79,9 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
7279
*/
7380
private final Map<String, String> explicitHibernateTypeParameters;
7481

82+
/**
83+
* The binding context
84+
*/
7585
private final AnnotationBindingContext context;
7686

7787
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> {
8090
this.name = name;
8191
this.attributeType = attributeType;
8292
this.accessType = accessType;
83-
84-
final AnnotationInstance typeAnnotation = JandexHelper.getSingleAnnotation(
85-
annotations(),
86-
HibernateDotNames.TYPE
87-
);
88-
if ( typeAnnotation != null ) {
89-
this.explicitHibernateTypeName = typeAnnotation.value( "type" ).asString();
90-
this.explicitHibernateTypeParameters = extractTypeParameters( typeAnnotation );
91-
}
92-
else {
93-
this.explicitHibernateTypeName = null;
94-
this.explicitHibernateTypeParameters = new HashMap<String, String>();
95-
}
96-
}
97-
98-
private Map<String, String> extractTypeParameters(AnnotationInstance typeAnnotation) {
99-
HashMap<String, String> typeParameters = new HashMap<String, String>();
100-
AnnotationValue parameterAnnotationValue = typeAnnotation.value( "parameters" );
101-
if ( parameterAnnotationValue != null ) {
102-
AnnotationInstance[] parameterAnnotations = parameterAnnotationValue.asNestedArray();
103-
for ( AnnotationInstance parameterAnnotationInstance : parameterAnnotations ) {
104-
typeParameters.put(
105-
parameterAnnotationInstance.value( "name" ).asString(),
106-
parameterAnnotationInstance.value( "value" ).asString()
107-
);
108-
}
109-
}
110-
return typeParameters;
93+
this.explicitHibernateTypeParameters = new HashMap<String, String>();
94+
this.explicitHibernateTypeName = determineExplicitHibernateTypeName();
11195
}
11296

11397
public String getName() {
@@ -151,6 +135,86 @@ public String toString() {
151135
sb.append( '}' );
152136
return sb.toString();
153137
}
138+
139+
private String getTemporalType() {
140+
final AnnotationInstance temporalAnnotation = JandexHelper.getSingleAnnotation(
141+
annotations(),
142+
JPADotNames.TEMPORAL
143+
);
144+
if ( isTemporalType( attributeType ) ) {
145+
if ( temporalAnnotation == null ) {
146+
//SPEC 11.1.47 The Temporal annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar.
147+
throw new AnnotationException( "Attribute " + name + " is a Temporal type, but no @Temporal annotation found." );
148+
}
149+
TemporalType temporalType = JandexHelper.getEnumValue( temporalAnnotation, "value", TemporalType.class );
150+
boolean isDate = Date.class.isAssignableFrom( attributeType );
151+
String type = null;
152+
switch ( temporalType ) {
153+
case DATE:
154+
type = isDate ? "date" : "calendar_date";
155+
break;
156+
case TIME:
157+
type = "time";
158+
if ( !isDate ) {
159+
throw new NotYetImplementedException( "Calendar cannot persist TIME only" );
160+
}
161+
break;
162+
case TIMESTAMP:
163+
type = isDate ? "timestamp" : "calendar";
164+
break;
165+
default:
166+
throw new AssertionFailure( "Unknown temporal type: " + temporalType );
167+
}
168+
return type;
169+
}
170+
else {
171+
if ( temporalAnnotation != null ) {
172+
throw new AnnotationException(
173+
"@Temporal should only be set on a java.util.Date or java.util.Calendar property: " + name
174+
);
175+
}
176+
}
177+
return null;
178+
}
179+
180+
private boolean isTemporalType(Class type) {
181+
return Date.class.isAssignableFrom( type ) || Calendar.class.isAssignableFrom( type );
182+
//todo (stliu) java.sql.Date is not listed in spec
183+
// || java.sql.Date.class.isAssignableFrom( type )
184+
}
185+
186+
private Map<String, String> extractTypeParameters(AnnotationInstance typeAnnotation) {
187+
HashMap<String, String> typeParameters = new HashMap<String, String>();
188+
AnnotationValue parameterAnnotationValue = typeAnnotation.value( "parameters" );
189+
if ( parameterAnnotationValue != null ) {
190+
AnnotationInstance[] parameterAnnotations = parameterAnnotationValue.asNestedArray();
191+
for ( AnnotationInstance parameterAnnotationInstance : parameterAnnotations ) {
192+
typeParameters.put(
193+
parameterAnnotationInstance.value( "name" ).asString(),
194+
parameterAnnotationInstance.value( "value" ).asString()
195+
);
196+
}
197+
}
198+
return typeParameters;
199+
}
200+
201+
private String determineExplicitHibernateTypeName() {
202+
String typeName = null;
203+
String temporalType = getTemporalType();
204+
final AnnotationInstance typeAnnotation = JandexHelper.getSingleAnnotation(
205+
annotations(),
206+
HibernateDotNames.TYPE
207+
);
208+
if ( typeAnnotation != null ) {
209+
typeName = typeAnnotation.value( "type" ).asString();
210+
this.explicitHibernateTypeParameters.putAll( extractTypeParameters( typeAnnotation ) );
211+
}
212+
else if ( temporalType != null ) {
213+
typeName = temporalType;
214+
215+
}
216+
return typeName;
217+
}
154218
}
155219

156220

hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/Binder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.hibernate.cfg.NotYetImplementedException;
3535
import org.hibernate.internal.util.StringHelper;
3636
import org.hibernate.internal.util.beans.BeanInfoHelper;
37+
import org.hibernate.internal.util.collections.CollectionHelper;
3738
import org.hibernate.metamodel.binding.AbstractPluralAttributeBinding;
3839
import org.hibernate.metamodel.binding.AttributeBinding;
3940
import org.hibernate.metamodel.binding.CollectionElementNature;
@@ -517,7 +518,7 @@ private void resolveTypeInformation(ExplicitHibernateTypeSource typeSource, Simp
517518
attributeBinding.getHibernateTypeDescriptor().setExplicitTypeName( explicitTypeName );
518519
}
519520
final Map<String, String> parameters = typeSource.getParameters();
520-
if ( parameters != null ) {
521+
if ( parameters!=null) {
521522
attributeBinding.getHibernateTypeDescriptor().getTypeParameters().putAll( parameters );
522523
}
523524
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.hibernate.metamodel.source.annotations.entity;
2+
3+
import java.util.Date;
4+
import javax.persistence.Entity;
5+
import javax.persistence.Id;
6+
import javax.persistence.Temporal;
7+
import javax.persistence.TemporalType;
8+
9+
import org.junit.Test;
10+
11+
import org.hibernate.AnnotationException;
12+
import org.hibernate.metamodel.binding.AttributeBinding;
13+
import org.hibernate.metamodel.binding.EntityBinding;
14+
import org.hibernate.metamodel.binding.HibernateTypeDescriptor;
15+
import org.hibernate.type.TimestampType;
16+
17+
import static org.junit.Assert.assertEquals;
18+
import static org.junit.Assert.assertNotNull;
19+
import static org.junit.Assert.assertTrue;
20+
21+
/**
22+
* @author Strong Liu
23+
*/
24+
public class TemporalBindingTests extends BaseAnnotationBindingTestCase {
25+
@Entity
26+
class Item1 {
27+
@Id
28+
long id;
29+
Date date;
30+
}
31+
32+
@Test(expected = AnnotationException.class)
33+
@Resources(annotatedClasses = TemporalBindingTests.Item1.class)
34+
public void testNoTemporalAnnotationOnTemporalTypeAttribute() {
35+
getEntityBinding( Item1.class );
36+
37+
}
38+
39+
@Entity
40+
class Item2 {
41+
@Id
42+
long id;
43+
@Temporal(TemporalType.TIMESTAMP)
44+
Date date;
45+
}
46+
47+
@Test
48+
@Resources(annotatedClasses = TemporalBindingTests.Item2.class)
49+
public void testTemporalTypeAttribute() {
50+
EntityBinding binding = getEntityBinding( Item2.class );
51+
AttributeBinding attributeBinding = binding.getAttributeBinding( "date" );
52+
HibernateTypeDescriptor descriptor = attributeBinding.getHibernateTypeDescriptor();
53+
assertEquals( "timestamp", descriptor.getExplicitTypeName() );
54+
assertEquals( Date.class.getName(), descriptor.getJavaTypeName() );
55+
assertNotNull( descriptor.getResolvedTypeMapping() );
56+
assertEquals( TimestampType.class, descriptor.getResolvedTypeMapping().getClass() );
57+
assertNotNull( descriptor.getTypeParameters() );
58+
assertTrue( descriptor.getTypeParameters().isEmpty() );
59+
}
60+
61+
@Entity
62+
class Item3 {
63+
@Id
64+
@Temporal(TemporalType.TIMESTAMP)
65+
Date date;
66+
}
67+
68+
@Test
69+
@Resources(annotatedClasses = TemporalBindingTests.Item3.class)
70+
public void testTemporalTypeAsId() {
71+
EntityBinding binding = getEntityBinding( Item3.class );
72+
AttributeBinding attributeBinding = binding.getAttributeBinding( "date" );
73+
HibernateTypeDescriptor descriptor = attributeBinding.getHibernateTypeDescriptor();
74+
assertEquals( "timestamp", descriptor.getExplicitTypeName() );
75+
assertEquals( Date.class.getName(), descriptor.getJavaTypeName() );
76+
assertNotNull( descriptor.getResolvedTypeMapping() );
77+
assertEquals( TimestampType.class, descriptor.getResolvedTypeMapping().getClass() );
78+
assertNotNull( descriptor.getTypeParameters() );
79+
assertTrue( descriptor.getTypeParameters().isEmpty() );
80+
}
81+
}

0 commit comments

Comments
 (0)