Skip to content

Commit

Permalink
HHH-6911 - Write DiscriminatorValue to DiscriminatorColumn when combi…
Browse files Browse the repository at this point in the history
…ned with InheritanceType#JOINED
  • Loading branch information
sebersole committed Dec 13, 2013
1 parent 5329bba commit b70148a
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 6 deletions.
Expand Up @@ -897,7 +897,11 @@ private static Ejb3DiscriminatorColumn processJoinedDiscriminatorProperties(

final DiscriminatorColumn discriminatorColumnAnnotation = clazzToProcess.getAnnotation( DiscriminatorColumn.class );
if ( !inheritanceState.hasParents() ) {
if ( discriminatorColumnAnnotation != null || mappings.useImplicitDiscriminatorColumnForJoinedInheritance() ) {
// we want to process the discriminator column if either:
// 1) There is an explicit DiscriminatorColumn annotation && we are not told to ignore them
// 2) There is not an explicit DiscriminatorColumn annotation && we are told to create them implicitly
if ( ( discriminatorColumnAnnotation != null && !mappings.ignoreExplicitDiscriminatorColumnForJoinedInheritance() )
|| ( discriminatorColumnAnnotation == null && mappings.useImplicitDiscriminatorColumnForJoinedInheritance() ) ) {
final DiscriminatorType discriminatorType = discriminatorColumnAnnotation != null
? discriminatorColumnAnnotation.discriminatorType()
: DiscriminatorType.STRING;
Expand Down
Expand Up @@ -614,11 +614,28 @@ public interface AvailableSettings {
* discriminator metadata means to follow the legacy behavior *unless* this setting is enabled. With this setting
* enabled, Hibernate will interpret the absence of discriminator metadata as an indication to use the JPA
* defined defaults for these absent annotations.
* <p/>
* See Hibernate Jira issue HHH-6911 for additional background info.
*
* See Hibernate Jira issue HHH-6911 for additional background info,
* @see #IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS
*/
String IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS = "hibernate.discriminator.implicit_for_joined";

/**
* The legacy behavior of Hibernate is to not use discriminators for joined inheritance (Hibernate does not need
* the discriminator...). However, some JPA providers do need the discriminator for handling joined inheritance.
* In the interest of portability this capability has been added to Hibernate too.
* <p/>
* Existing applications rely (implicitly or explicitly) on Hibernate ignoring any DiscriminatorColumn declarations
* on joined inheritance hierarchies. This setting allows these applications to maintain the legacy behavior
* of DiscriminatorColumn annotations being ignored when paired with joined inheritance.
* <p/>
* See Hibernate Jira issue HHH-6911 for additional background info.
*
* @see #IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS
*/
String IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS = "hibernate.discriminator.ignore_explicit_for_joined";

String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans";

String HQL_BULK_ID_STRATEGY = "hibernate.hql.bulk_id_strategy";
Expand Down
13 changes: 13 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java
Expand Up @@ -3400,6 +3400,19 @@ public boolean useImplicitDiscriminatorColumnForJoinedInheritance() {
}


private Boolean ignoreExplicitDiscriminatorColumnForJoinedInheritance;

@Override
public boolean ignoreExplicitDiscriminatorColumnForJoinedInheritance() {
if ( ignoreExplicitDiscriminatorColumnForJoinedInheritance == null ) {
final String booleanName = getConfigurationProperties()
.getProperty( AvailableSettings.IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS );
ignoreExplicitDiscriminatorColumnForJoinedInheritance = Boolean.valueOf( booleanName );
}
return ignoreExplicitDiscriminatorColumnForJoinedInheritance;
}


private Boolean useNationalizedCharacterData;

@Override
Expand Down
18 changes: 14 additions & 4 deletions hibernate-core/src/main/java/org/hibernate/cfg/Mappings.java
Expand Up @@ -798,16 +798,26 @@ public PropertyReference(String referencedClass, String propertyName, boolean un
public boolean useNewGeneratorMappings();

/**
* Should we handle discriminators for joined inheritance per legacy Hibernate rules, or
* Should we use the new generator strategy mappings. This is controlled by the
* {@link AvailableSettings#USE_NEW_ID_GENERATOR_MAPPINGS} setting.
* Should we handle absent DiscriminatorColumn mappings for joined inheritance by implicitly mapping a
* discriminator column?
*
* @return True if the new generators should be used, false otherwise.
* @return {@code true} indicates we should infer DiscriminatorColumn implicitly (aka, map to a discriminator
* column even without a DiscriminatorColumn annotation); {@code false} (the default) indicates that we should not.
*
* @see AvailableSettings#IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS
*/
public boolean useImplicitDiscriminatorColumnForJoinedInheritance();

/**
* Should we ignore explicit DiscriminatorColumn annotations when combined with joined inheritance?
*
* @return {@code true} indicates we should ignore explicit DiscriminatorColumn annotations; {@code false} (the
* default) indicates we should not ignore them
*
* @see AvailableSettings#IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS
*/
public boolean ignoreExplicitDiscriminatorColumnForJoinedInheritance();

/**
* Should we use nationalized variants of character data by default? This is controlled by the
* {@link AvailableSettings#USE_NATIONALIZED_CHARACTER_DATA} setting.
Expand Down
@@ -0,0 +1,122 @@
package org.hibernate.test.joinedsubclass;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;

import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;

import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
* @author Steve Ebersole
*/
@TestForIssue( jiraKey = "HHH-6911" )
public class JoinedSubclassWithIgnoredExplicitDiscriminatorTest extends BaseCoreFunctionalTestCase {
@Entity( name = "Animal" )
@Table( name = "animal" )
@Inheritance( strategy = InheritanceType.JOINED )
@DiscriminatorColumn( name = "type", discriminatorType = DiscriminatorType.STRING )
@DiscriminatorValue( value = "???animal???" )
public static abstract class Animal {
@Id
public Integer id;

protected Animal() {
}

protected Animal(Integer id) {
this.id = id;
}
}

@Entity( name = "Cat" )
@DiscriminatorValue( value = "cat" )
public static class Cat extends Animal {
public Cat() {
super();
}

public Cat(Integer id) {
super( id );
}
}

@Entity( name = "Dog" )
@DiscriminatorValue( value = "dog" )
public static class Dog extends Animal {
public Dog() {
super();
}

public Dog(Integer id) {
super( id );
}
}

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Animal.class, Cat.class, Dog.class };
}

@Override
protected void configure(Configuration configuration) {
super.configure( configuration );
configuration.setProperty( AvailableSettings.IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS, "true" );
}

@Test
public void metadataAssertions() {
EntityPersister p = sessionFactory().getEntityPersister( Dog.class.getName() );
assertNotNull( p );
final JoinedSubclassEntityPersister dogPersister = assertTyping( JoinedSubclassEntityPersister.class, p );
assertEquals( "integer", dogPersister.getDiscriminatorType().getName() );
assertEquals( "clazz_", dogPersister.getDiscriminatorColumnName() );
assertTrue( Integer.class.isInstance( dogPersister.getDiscriminatorValue() ) );

p = sessionFactory().getEntityPersister( Cat.class.getName() );
assertNotNull( p );
final JoinedSubclassEntityPersister catPersister = assertTyping( JoinedSubclassEntityPersister.class, p );
assertEquals( "integer", catPersister.getDiscriminatorType().getName() );
assertEquals( "clazz_", catPersister.getDiscriminatorColumnName() );
assertTrue( Integer.class.isInstance( catPersister.getDiscriminatorValue() ) );
}

@Test
public void basicUsageTest() {
Session session = openSession();
session.beginTransaction();
session.save( new Cat( 1 ) );
session.save( new Dog( 2 ) );
session.getTransaction().commit();
session.close();

session = openSession();
session.beginTransaction();
session.createQuery( "from Animal" ).list();
Cat cat = (Cat) session.get( Cat.class, 1 );
assertNotNull( cat );
session.delete( cat );
Dog dog = (Dog) session.get( Dog.class, 2 );
assertNotNull( dog );
session.delete( dog );
session.getTransaction().commit();
session.close();
}
}

0 comments on commit b70148a

Please sign in to comment.