HHH-6300 Adding support for custom sql via @SqlInsert, @SqlUpdate, @SqlDelete and @SqlDeleteAll
This commit is contained in:
parent
a2982ea939
commit
24bd525693
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue