HHH-6300 Adding support for custom sql via @SqlInsert, @SqlUpdate, @SqlDelete and @SqlDeleteAll

This commit is contained in:
Hardy Ferentschik 2011-06-14 12:40:14 +02:00
parent a2982ea939
commit 24bd525693
5 changed files with 187 additions and 22 deletions

View File

@ -26,10 +26,10 @@ package org.hibernate.metamodel.binding;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
/**
* TODO : javadoc
*
* @author Steve Ebersole
*/
* Wraps the information for custom SQL execution
*
* @author Steve Ebersole
*/
public class CustomSQL {
private final String sql;
private final boolean isCallable;

View File

@ -38,10 +38,13 @@ import org.hibernate.MappingException;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.PolymorphismType;
import org.hibernate.annotations.ResultCheckStyle;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.CustomSQL;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.EntityDiscriminator;
import org.hibernate.metamodel.binding.IdGenerator;
@ -101,6 +104,7 @@ public class EntityBinder {
bindHibernateCaching( entityBindingState );
bindProxy( entityBindingState );
bindSynchronize( entityBindingState );
bindCustomSQL( entityBindingState );
// take care of the id, attributes and relations
if ( configuredClass.isRoot() ) {
@ -273,6 +277,55 @@ public class EntityBinder {
}
}
private void bindCustomSQL(EntityBindingStateImpl entityBindingState) {
AnnotationInstance sqlInsertAnnotation = JandexHelper.getSingleAnnotation(
configuredClass.getClassInfo(), HibernateDotNames.SQL_INSERT
);
entityBindingState.setCustomInsert( createCustomSQL( sqlInsertAnnotation ) );
AnnotationInstance sqlUpdateAnnotation = JandexHelper.getSingleAnnotation(
configuredClass.getClassInfo(), HibernateDotNames.SQL_UPDATE
);
entityBindingState.setCustomUpdate( createCustomSQL( sqlUpdateAnnotation ) );
AnnotationInstance sqlDeleteAnnotation = JandexHelper.getSingleAnnotation(
configuredClass.getClassInfo(), HibernateDotNames.SQL_DELETE
);
entityBindingState.setCustomDelete( createCustomSQL( sqlDeleteAnnotation ) );
AnnotationInstance sqlDeleteAllAnnotation = JandexHelper.getSingleAnnotation(
configuredClass.getClassInfo(), HibernateDotNames.SQL_DELETE_ALL
);
if ( sqlDeleteAllAnnotation != null ) {
entityBindingState.setCustomDelete( createCustomSQL( sqlDeleteAllAnnotation ) );
}
}
private CustomSQL createCustomSQL(AnnotationInstance customSQLAnnotation) {
if ( customSQLAnnotation == null ) {
return null;
}
String sql = customSQLAnnotation.value( "sql" ).asString();
boolean isCallable = false;
AnnotationValue callableValue = customSQLAnnotation.value( "callable" );
if ( callableValue != null ) {
isCallable = callableValue.asBoolean();
}
ResultCheckStyle checkStyle = ResultCheckStyle.NONE;
AnnotationValue checkStyleValue = customSQLAnnotation.value( "check" );
if ( checkStyleValue != null ) {
checkStyle = Enum.valueOf( ResultCheckStyle.class, checkStyleValue.asEnum() );
}
return new CustomSQL(
sql,
isCallable,
Enum.valueOf( ExecuteUpdateResultCheckStyle.class, checkStyle.toString() )
);
}
private Caching createCachingForCacheableAnnotation(EntityBindingStateImpl entityBindingState) {
String region = entityBindingState.getEntityName();
RegionFactory regionFactory = meta.getServiceRegistry().getService( RegionFactory.class );

View File

@ -80,9 +80,6 @@ public class EntityBindingStateImpl implements EntityBindingState {
this.rowId = null;
this.batchSize = -1;
this.isAbstract = false;
this.customInsert = null;
this.customUpdate = null;
this.customDelete = null;
}
public void setEntityName(String entityName) {
@ -141,6 +138,18 @@ public class EntityBindingStateImpl implements EntityBindingState {
synchronizedTableNames.add( tableName );
}
public void setCustomInsert(CustomSQL customInsert) {
this.customInsert = customInsert;
}
public void setCustomUpdate(CustomSQL customUpdate) {
this.customUpdate = customUpdate;
}
public void setCustomDelete(CustomSQL customDelete) {
this.customDelete = customDelete;
}
@Override
public boolean isRoot() {
return isRoot;

View File

@ -52,13 +52,10 @@ import org.hibernate.service.classloading.spi.ClassLoaderService;
* @author Hardy Ferentschik
*/
public class JandexHelper {
private static final AnnotationInstance[] EMPTY_ANNOTATIONS_ARRAY = new AnnotationInstance[0];
private static final Map<String, Object> DEFAULT_VALUES_BY_ELEMENT = new HashMap<String, Object>();
private static Object getDefaultValue(AnnotationInstance annotation,
String element) {
private static Object getDefaultValue(AnnotationInstance annotation, String element) {
String name = annotation.name().toString();
String fqElement = name + '.' + element;
Object val = DEFAULT_VALUES_BY_ELEMENT.get( fqElement );
@ -164,8 +161,7 @@ public class JandexHelper {
* @return the value if not <code>null</code>, else the default value if not
* <code>null</code>, else <code>null</code>.
*/
public static Object getValue(AnnotationInstance annotation,
String element) {
public static Object getValue(AnnotationInstance annotation, String element) {
AnnotationValue val = annotation.value( element );
if ( val == null ) {
return getDefaultValue( annotation, element );
@ -182,8 +178,7 @@ public class JandexHelper {
*
* @return the element array if not <code>null</code>, else an empty array
*/
public static AnnotationInstance[] getValueAsArray(AnnotationInstance annotation,
String element) {
public static AnnotationInstance[] getValueAsArray(AnnotationInstance annotation, String element) {
AnnotationValue val = annotation.value( element );
return val == null ? EMPTY_ANNOTATIONS_ARRAY : val.asNestedArray();
}
@ -202,9 +197,7 @@ public class JandexHelper {
*
* @see #getValue(AnnotationInstance, String)
*/
public static <T extends Enum<T>> T getValueAsEnum(AnnotationInstance annotation,
String element,
Class<T> type) {
public static <T extends Enum<T>> T getValueAsEnum(AnnotationInstance annotation, String element, Class<T> type) {
AnnotationValue val = annotation.value( element );
if ( val == null ) {
return (T) getDefaultValue( annotation, element );
@ -222,8 +215,7 @@ public class JandexHelper {
* @return the value converted to an int if the value is not <code>null</code>, else the default value if not
* <code>null</code>, else <code>0</code>.
*/
public static int getValueAsInt(AnnotationInstance annotation,
String element) {
public static int getValueAsInt(AnnotationInstance annotation, String element) {
AnnotationValue val = annotation.value( element );
if ( val == null ) {
return (Integer) getDefaultValue( annotation, element );
@ -241,8 +233,7 @@ public class JandexHelper {
* @return the value converted to a String if the value is not <code>null</code>, else the default value if not
* <code>null</code>, else <code>null</code>.
*/
public static String getValueAsString(AnnotationInstance annotation,
String element) {
public static String getValueAsString(AnnotationInstance annotation, String element) {
AnnotationValue val = annotation.value( element );
if ( val == null ) {
return (String) getDefaultValue( annotation, element );

View File

@ -0,0 +1,112 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.source.annotations.entity;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.Test;
import org.hibernate.annotations.ResultCheckStyle;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLDeleteAll;
import org.hibernate.annotations.SQLInsert;
import org.hibernate.annotations.SQLUpdate;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.metamodel.binding.CustomSQL;
import org.hibernate.metamodel.binding.EntityBinding;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
/**
* Tests for {@code o.h.a.SQLInsert}, {@code o.h.a.SQLUpdate}, {@code o.h.a.Delete} and {@code o.h.a.SQLDeleteAll}.
*
* @author Hardy Ferentschik
*/
public class CustomSQLTests extends BaseAnnotationBindingTestCase {
@Test
public void testNoCustomSqlAnnotations() {
buildMetadataSources( NoCustomSQLEntity.class );
EntityBinding binding = getEntityBinding( NoCustomSQLEntity.class );
assertNull( binding.getCustomDelete() );
assertNull( binding.getCustomInsert() );
assertNull( binding.getCustomUpdate() );
}
@Test
public void testCustomSqlAnnotations() {
buildMetadataSources( CustomSQLEntity.class );
EntityBinding binding = getEntityBinding( CustomSQLEntity.class );
CustomSQL customSql = binding.getCustomInsert();
assertCustomSql( customSql, "INSERT INTO FOO", true, ExecuteUpdateResultCheckStyle.NONE );
customSql = binding.getCustomDelete();
assertCustomSql( customSql, "DELETE FROM FOO", false, ExecuteUpdateResultCheckStyle.COUNT );
customSql = binding.getCustomUpdate();
assertCustomSql( customSql, "UPDATE FOO", false, ExecuteUpdateResultCheckStyle.PARAM );
}
@Test
public void testDeleteAllWins() {
buildMetadataSources( CustomDeleteAllEntity.class );
EntityBinding binding = getEntityBinding( CustomDeleteAllEntity.class );
assertEquals( "Wrong sql", "DELETE ALL", binding.getCustomDelete().getSql() );
}
private void assertCustomSql(CustomSQL customSql, String sql, boolean isCallable, ExecuteUpdateResultCheckStyle style) {
assertNotNull( customSql );
assertEquals( "Wrong sql", sql, customSql.getSql() );
assertEquals( isCallable, customSql.isCallable() );
assertEquals( style, customSql.getCheckStyle() );
}
@Entity
class NoCustomSQLEntity {
@Id
private int id;
}
@Entity
@SQLInsert(sql = "INSERT INTO FOO", callable = true)
@SQLDelete(sql = "DELETE FROM FOO", check = ResultCheckStyle.COUNT)
@SQLUpdate(sql = "UPDATE FOO", check = ResultCheckStyle.PARAM)
class CustomSQLEntity {
@Id
private int id;
}
@Entity
@SQLDelete(sql = "DELETE")
@SQLDeleteAll(sql = "DELETE ALL")
class CustomDeleteAllEntity {
@Id
private int id;
}
}