HHH-6562 - Unknown collection role when accessing ElementCollection in Embeddable via Criteria API
This commit is contained in:
parent
20c2037529
commit
774a16c2d9
|
@ -11,9 +11,12 @@ import javax.persistence.metamodel.Attribute;
|
||||||
import javax.persistence.metamodel.Bindable;
|
import javax.persistence.metamodel.Bindable;
|
||||||
import javax.persistence.metamodel.EntityType;
|
import javax.persistence.metamodel.EntityType;
|
||||||
import javax.persistence.metamodel.IdentifiableType;
|
import javax.persistence.metamodel.IdentifiableType;
|
||||||
|
import javax.persistence.metamodel.MappedSuperclassType;
|
||||||
import javax.persistence.metamodel.PluralAttribute;
|
import javax.persistence.metamodel.PluralAttribute;
|
||||||
|
import javax.persistence.metamodel.SingularAttribute;
|
||||||
import javax.persistence.metamodel.Type;
|
import javax.persistence.metamodel.Type;
|
||||||
|
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
|
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
|
||||||
import org.hibernate.query.criteria.internal.PathSource;
|
import org.hibernate.query.criteria.internal.PathSource;
|
||||||
|
@ -44,39 +47,73 @@ public class PluralAttributePath<X> extends AbstractPathImpl<X> implements Seria
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveRole(PluralAttribute attribute) {
|
private String resolveRole(PluralAttribute attribute) {
|
||||||
Class<?> roleOwnerType = attribute.getDeclaringType().getJavaType();
|
switch ( attribute.getDeclaringType().getPersistenceType() ) {
|
||||||
if ( attribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.MAPPED_SUPERCLASS ) {
|
case ENTITY: {
|
||||||
// the attribute is declared in a mappedsuperclass
|
return attribute.getDeclaringType().getJavaType().getName() + '.' + attribute.getName();
|
||||||
if ( getPathSource().getModel().getBindableType() == Bindable.BindableType.ENTITY_TYPE ) {
|
|
||||||
// the role will be assigned to the "nearest" EnityType subclass of the MappedSuperclassType
|
|
||||||
EntityType entityTypeNearestDeclaringType = (EntityType) getPathSource().getModel();
|
|
||||||
IdentifiableType superType = entityTypeNearestDeclaringType.getSupertype();
|
|
||||||
IdentifiableType previousType = entityTypeNearestDeclaringType;
|
|
||||||
while ( superType != attribute.getDeclaringType() ) {
|
|
||||||
if ( superType == null ) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
String.format(
|
|
||||||
"Cannot determine nearest EntityType extending mapped superclass [%s]; [%s] extends [%s], but supertype of [%s] is null",
|
|
||||||
attribute.getDeclaringType().getJavaType().getName(),
|
|
||||||
( (EntityType) getPathSource().getModel() ).getJavaType().getName(),
|
|
||||||
previousType.getJavaType().getName(),
|
|
||||||
previousType.getJavaType().getName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ( superType.getPersistenceType() == Type.PersistenceType.ENTITY ) {
|
|
||||||
entityTypeNearestDeclaringType = (EntityType) superType;
|
|
||||||
}
|
|
||||||
previousType = superType;
|
|
||||||
superType = superType.getSupertype();
|
|
||||||
}
|
|
||||||
roleOwnerType = entityTypeNearestDeclaringType.getJavaType();
|
|
||||||
}
|
}
|
||||||
// else throw an exception?
|
case MAPPED_SUPERCLASS: {
|
||||||
|
// the attribute is declared in a mappedsuperclass
|
||||||
|
if ( getPathSource().getModel().getBindableType() == Bindable.BindableType.ENTITY_TYPE ) {
|
||||||
|
// the role will be assigned to the "nearest" EnityType subclass of the MappedSuperclassType
|
||||||
|
final EntityType entityTypeNearestDeclaringType = locateNearestSubclassEntity(
|
||||||
|
(MappedSuperclassType) attribute.getDeclaringType(),
|
||||||
|
(EntityType) getPathSource().getModel()
|
||||||
|
);
|
||||||
|
return entityTypeNearestDeclaringType.getJavaType().getName() + '.' + attribute.getName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new AssertionFailure(
|
||||||
|
String.format(
|
||||||
|
"Unexpected BindableType; expected [%s]; instead got [%s]",
|
||||||
|
Bindable.BindableType.ENTITY_TYPE,
|
||||||
|
getPathSource().getModel().getBindableType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case EMBEDDABLE: {
|
||||||
|
// initialize role to '.' + <plural_attribute_name>
|
||||||
|
StringBuilder role = new StringBuilder().append( '.' ).append( attribute.getName() );
|
||||||
|
PathSource parentPath = getPathSource();
|
||||||
|
SingularAttribute singularAttribute;
|
||||||
|
do {
|
||||||
|
final SingularAttributePath singularAttributePath = (SingularAttributePath) parentPath;
|
||||||
|
singularAttribute = singularAttributePath.getAttribute();
|
||||||
|
// insert '.' + <parent_embeddable_attribute_name> at start of role
|
||||||
|
role.insert( 0, '.' );
|
||||||
|
role.insert( 1, singularAttributePath.getAttribute().getName() );
|
||||||
|
parentPath = singularAttributePath.getPathSource();
|
||||||
|
} while ( ( SingularAttributePath.class.isInstance( parentPath ) ) );
|
||||||
|
final EntityType entityType;
|
||||||
|
if ( singularAttribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.ENTITY ) {
|
||||||
|
entityType = (EntityType) singularAttribute.getDeclaringType();
|
||||||
|
}
|
||||||
|
else if ( singularAttribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.MAPPED_SUPERCLASS ){
|
||||||
|
// find the "nearest" EnityType subclass of the MappedSuperclassType
|
||||||
|
entityType = locateNearestSubclassEntity(
|
||||||
|
(MappedSuperclassType) singularAttribute.getDeclaringType(),
|
||||||
|
(EntityType) parentPath.getModel()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new AssertionFailure(
|
||||||
|
String.format(
|
||||||
|
"Unexpected PersistenceType: [%s]",
|
||||||
|
singularAttribute.getDeclaringType().getPersistenceType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// insert <entity_name> at start of role
|
||||||
|
return role.insert( 0, entityType.getJavaType().getName() ).toString();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new AssertionFailure(
|
||||||
|
String.format(
|
||||||
|
"Unexpected PersistenceType: [%s]",
|
||||||
|
attribute.getDeclaringType().getPersistenceType()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// TODO: still need to deal with a plural attribute declared in an embeddable (HHH-6562)
|
|
||||||
return roleOwnerType.getName() +
|
|
||||||
'.' + attribute.getName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluralAttribute<?,X,?> getAttribute() {
|
public PluralAttribute<?,X,?> getAttribute() {
|
||||||
|
@ -115,4 +152,26 @@ public class PluralAttributePath<X> extends AbstractPathImpl<X> implements Seria
|
||||||
+ attribute.getName() + "] cannot be dereferenced"
|
+ attribute.getName() + "] cannot be dereferenced"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EntityType locateNearestSubclassEntity(MappedSuperclassType mappedSuperclassType, EntityType entityTypeTop) {
|
||||||
|
EntityType entityTypeNearestDeclaringType = entityTypeTop;
|
||||||
|
IdentifiableType superType = entityTypeNearestDeclaringType.getSupertype();
|
||||||
|
while ( superType != mappedSuperclassType ) {
|
||||||
|
if ( superType == null ) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
String.format(
|
||||||
|
"Cannot determine nearest EntityType extending mapped superclass [%s] starting from [%s]; a supertype of [%s] is null",
|
||||||
|
mappedSuperclassType.getJavaType().getName(),
|
||||||
|
entityTypeTop.getJavaType().getName(),
|
||||||
|
entityTypeTop.getJavaType().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( superType.getPersistenceType() == Type.PersistenceType.ENTITY ) {
|
||||||
|
entityTypeNearestDeclaringType = (EntityType) superType;
|
||||||
|
}
|
||||||
|
superType = superType.getSupertype();
|
||||||
|
}
|
||||||
|
return entityTypeNearestDeclaringType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,351 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.test.criteria.components;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.Embedded;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
import javax.persistence.criteria.Root;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.transaction.TransactionUtil;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-6562")
|
||||||
|
public class ComponentInWhereClauseTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
private Projects projects;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {Employee.class, Project.class, Person.class};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
projects = new Projects();
|
||||||
|
projects.addPreviousProject( new Project( "First" ) );
|
||||||
|
projects.addPreviousProject( new Project( "Second" ) );
|
||||||
|
projects.setCurrentProject( new Project( "Third" ) );
|
||||||
|
|
||||||
|
ContactDetail contactDetail = new ContactDetail();
|
||||||
|
contactDetail.setEmail( "abc@mail.org" );
|
||||||
|
contactDetail.addPhone( new Phone( "+4411111111" ) );
|
||||||
|
|
||||||
|
final Employee employee = new Employee();
|
||||||
|
employee.setProjects( projects );
|
||||||
|
employee.setContactDetail( contactDetail );
|
||||||
|
entityManager.persist( employee );
|
||||||
|
|
||||||
|
final Person person = new Person();
|
||||||
|
person.setInformation( new Information() );
|
||||||
|
ContactDetail infoContactDetail = new ContactDetail();
|
||||||
|
infoContactDetail.setEmail( "xyz@mail.org" );
|
||||||
|
infoContactDetail.addPhone( new Phone( "999-999-9999" ) );
|
||||||
|
person.getInformation().setInfoContactDetail( infoContactDetail );
|
||||||
|
entityManager.persist( person );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheOneToManyPropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||||
|
Root<Employee> root = query.from( Employee.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "projects" ).get( "previousProjects" ) )
|
||||||
|
, 2 ) );
|
||||||
|
|
||||||
|
final List<Employee> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheElementCollectionPropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||||
|
Root<Employee> root = query.from( Employee.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "contactDetail" ).get( "phones" ) )
|
||||||
|
, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Employee> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheElementCollectionPropertyOfASubComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Person> query = builder.createQuery( Person.class );
|
||||||
|
Root<Person> root = query.from( Person.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "information" ).get( "infoContactDetail" ).get( "phones" ) )
|
||||||
|
, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Person> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEqualExpressionForThePropertyOfTheElementCollectionPropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||||
|
Root<Employee> root = query.from( Employee.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
root.join( "contactDetail" ).join( "phones" ).get( "number" )
|
||||||
|
, "+4411111111" )
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Employee> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEqualityForThePropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||||
|
Root<Employee> root = query.from( Employee.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
root.join( "contactDetail" ).get( "email" )
|
||||||
|
, "abc@mail.org"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Employee> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInExpressionForAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||||
|
Root<Employee> root = query.from( Employee.class );
|
||||||
|
|
||||||
|
query.where( root.get( "projects" ).in( projects, new Projects() ) );
|
||||||
|
|
||||||
|
final List<Employee> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInExpressionForTheManyToOnePropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||||
|
Root<Employee> root = query.from( Employee.class );
|
||||||
|
|
||||||
|
query.where( root.get( "projects" )
|
||||||
|
.get( "currentProject" )
|
||||||
|
.in( projects.getCurrentProject() ) );
|
||||||
|
|
||||||
|
final List<Employee> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static abstract class AbstractEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
protected Long id;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Employee")
|
||||||
|
@Table(name = "EMPLOYEE")
|
||||||
|
public static class Employee extends AbstractEntity {
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Projects projects;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private ContactDetail contactDetail;
|
||||||
|
|
||||||
|
public void setProjects(Projects projects) {
|
||||||
|
this.projects = projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactDetail(ContactDetail contactDetail) {
|
||||||
|
this.contactDetail = contactDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class ContactDetail {
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
private List<Phone> phones = new ArrayList<>();
|
||||||
|
|
||||||
|
public void addPhone(Phone phone) {
|
||||||
|
this.phones.add( phone );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Projects {
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.PERSIST)
|
||||||
|
private Set<Project> previousProjects = new HashSet<>();
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||||
|
private Project currentProject;
|
||||||
|
|
||||||
|
public void setCurrentProject(Project project) {
|
||||||
|
this.currentProject = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPreviousProject(Project project) {
|
||||||
|
this.previousProjects.add( project );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Project> getPreviousProjects() {
|
||||||
|
return previousProjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project getCurrentProject() {
|
||||||
|
return currentProject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Project")
|
||||||
|
@Table(name = "PROJECT")
|
||||||
|
public static class Project extends AbstractEntity {
|
||||||
|
|
||||||
|
public Project() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Phone {
|
||||||
|
private String number;
|
||||||
|
|
||||||
|
public Phone() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Phone(String number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumber() {
|
||||||
|
return this.number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Person")
|
||||||
|
@Table(name="PERSON")
|
||||||
|
public static class Person extends AbstractEntity {
|
||||||
|
@Embedded
|
||||||
|
private Information information;
|
||||||
|
|
||||||
|
public Information getInformation() {
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInformation(Information information) {
|
||||||
|
this.information = information;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Information {
|
||||||
|
@Embedded
|
||||||
|
private ContactDetail infoContactDetail;
|
||||||
|
|
||||||
|
public ContactDetail getInfoContactDetail() {
|
||||||
|
return infoContactDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfoContactDetail(ContactDetail infoContactDetail) {
|
||||||
|
this.infoContactDetail = infoContactDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,289 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.test.criteria.components;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.Embedded;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
import javax.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.transaction.TransactionUtil;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-6562")
|
||||||
|
public class EntitySuperclassComponentWithCollectionTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
private Projects projects;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {Employee.class, Manager.class, Project.class, Person.class, Leader.class};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
projects = new Projects();
|
||||||
|
projects.addPreviousProject( new Project( "First" ) );
|
||||||
|
projects.addPreviousProject( new Project( "Second" ) );
|
||||||
|
projects.setCurrentProject( new Project( "Third" ) );
|
||||||
|
|
||||||
|
ContactDetail contactDetail = new ContactDetail();
|
||||||
|
contactDetail.setEmail( "abc@mail.org" );
|
||||||
|
contactDetail.addPhone( new Phone( "+4411111111" ) );
|
||||||
|
|
||||||
|
final Manager manager = new Manager();
|
||||||
|
manager.setProjects( projects );
|
||||||
|
manager.setContactDetail( contactDetail );
|
||||||
|
entityManager.persist( manager );
|
||||||
|
|
||||||
|
final Leader leader = new Leader();
|
||||||
|
leader.setInformation( new Information() );
|
||||||
|
ContactDetail infoContactDetail = new ContactDetail();
|
||||||
|
infoContactDetail.setEmail( "xyz@mail.org" );
|
||||||
|
infoContactDetail.addPhone( new Phone( "999-999-9999" ) );
|
||||||
|
leader.getInformation().setInfoContactDetail( infoContactDetail );
|
||||||
|
entityManager.persist( leader );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheOneToManyPropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Manager> query = builder.createQuery( Manager.class );
|
||||||
|
Root<Manager> root = query.from( Manager.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "projects" ).get( "previousProjects" ) )
|
||||||
|
, 2 ) );
|
||||||
|
|
||||||
|
final List<Manager> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheElementCollectionPropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Manager> query = builder.createQuery( Manager.class );
|
||||||
|
Root<Manager> root = query.from( Manager.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "contactDetail" ).get( "phones" ) )
|
||||||
|
, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Manager> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheElementCollectionPropertyOfASubComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Leader> query = builder.createQuery( Leader.class );
|
||||||
|
Root<Leader> root = query.from( Leader.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "information" ).get( "infoContactDetail" ).get( "phones" ) )
|
||||||
|
, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Leader> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static abstract class AbstractEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
protected Long id;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Employee")
|
||||||
|
@Table(name = "EMPLOYEE")
|
||||||
|
public static class Employee extends AbstractEntity {
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Projects projects;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private ContactDetail contactDetail;
|
||||||
|
|
||||||
|
public void setProjects(Projects projects) {
|
||||||
|
this.projects = projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactDetail(ContactDetail contactDetail) {
|
||||||
|
this.contactDetail = contactDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Manager")
|
||||||
|
@Table(name = "MANAGER")
|
||||||
|
public static class Manager extends Employee {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class ContactDetail {
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
private List<Phone> phones = new ArrayList<>();
|
||||||
|
|
||||||
|
public void addPhone(Phone phone) {
|
||||||
|
this.phones.add( phone );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Projects {
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.PERSIST)
|
||||||
|
private Set<Project> previousProjects = new HashSet<>();
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||||
|
private Project currentProject;
|
||||||
|
|
||||||
|
public void setCurrentProject(Project project) {
|
||||||
|
this.currentProject = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPreviousProject(Project project) {
|
||||||
|
this.previousProjects.add( project );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Project> getPreviousProjects() {
|
||||||
|
return previousProjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project getCurrentProject() {
|
||||||
|
return currentProject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Project")
|
||||||
|
@Table(name = "PROJECT")
|
||||||
|
public static class Project extends AbstractEntity {
|
||||||
|
|
||||||
|
public Project() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Phone {
|
||||||
|
private String number;
|
||||||
|
|
||||||
|
public Phone() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Phone(String number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumber() {
|
||||||
|
return this.number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Person")
|
||||||
|
@Table(name="PERSON")
|
||||||
|
public static class Person extends AbstractEntity {
|
||||||
|
@Embedded
|
||||||
|
private Information information;
|
||||||
|
|
||||||
|
public Information getInformation() {
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInformation(Information information) {
|
||||||
|
this.information = information;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name="Leader")
|
||||||
|
@Table(name="LEADER")
|
||||||
|
public static class Leader extends Person {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Information {
|
||||||
|
@Embedded
|
||||||
|
private ContactDetail infoContactDetail;
|
||||||
|
|
||||||
|
public ContactDetail getInfoContactDetail() {
|
||||||
|
return infoContactDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfoContactDetail(ContactDetail infoContactDetail) {
|
||||||
|
this.infoContactDetail = infoContactDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.test.criteria.components;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.Embedded;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
import javax.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.transaction.TransactionUtil;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-6562")
|
||||||
|
public class MappedSuperclassComponentWithCollectionTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
private Projects projects;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {Employee.class, Manager.class, Project.class, Person.class, Leader.class};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
projects = new Projects();
|
||||||
|
projects.addPreviousProject( new Project( "First" ) );
|
||||||
|
projects.addPreviousProject( new Project( "Second" ) );
|
||||||
|
projects.setCurrentProject( new Project( "Third" ) );
|
||||||
|
|
||||||
|
ContactDetail contactDetail = new ContactDetail();
|
||||||
|
contactDetail.setEmail( "abc@mail.org" );
|
||||||
|
contactDetail.addPhone( new Phone( "+4411111111" ) );
|
||||||
|
|
||||||
|
final Manager manager = new Manager();
|
||||||
|
manager.setProjects( projects );
|
||||||
|
manager.setContactDetail( contactDetail );
|
||||||
|
entityManager.persist( manager );
|
||||||
|
|
||||||
|
final Leader leader = new Leader();
|
||||||
|
leader.setInformation( new Information() );
|
||||||
|
ContactDetail infoContactDetail = new ContactDetail();
|
||||||
|
infoContactDetail.setEmail( "xyz@mail.org" );
|
||||||
|
infoContactDetail.addPhone( new Phone( "999-999-9999" ) );
|
||||||
|
leader.getInformation().setInfoContactDetail( infoContactDetail );
|
||||||
|
entityManager.persist( leader );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheOneToManyPropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Manager> query = builder.createQuery( Manager.class );
|
||||||
|
Root<Manager> root = query.from( Manager.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "projects" ).get( "previousProjects" ) )
|
||||||
|
, 2 ) );
|
||||||
|
|
||||||
|
final List<Manager> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheElementCollectionPropertyOfAComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Manager> query = builder.createQuery( Manager.class );
|
||||||
|
Root<Manager> root = query.from( Manager.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "contactDetail" ).get( "phones" ) )
|
||||||
|
, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Manager> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeExpressionForTheElementCollectionPropertyOfASubComponent() {
|
||||||
|
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Leader> query = builder.createQuery( Leader.class );
|
||||||
|
Root<Leader> root = query.from( Leader.class );
|
||||||
|
|
||||||
|
query.where(
|
||||||
|
builder.equal(
|
||||||
|
builder.size( root.get( "information" ).get( "infoContactDetail" ).get( "phones" ) )
|
||||||
|
, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Leader> results = entityManager.createQuery( query ).getResultList();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static abstract class AbstractEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
protected Long id;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static class Employee extends AbstractEntity {
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Projects projects;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private ContactDetail contactDetail;
|
||||||
|
|
||||||
|
public void setProjects(Projects projects) {
|
||||||
|
this.projects = projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContactDetail(ContactDetail contactDetail) {
|
||||||
|
this.contactDetail = contactDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Manager")
|
||||||
|
@Table(name = "MANAGER")
|
||||||
|
public static class Manager extends Employee {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class ContactDetail {
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
private List<Phone> phones = new ArrayList<>();
|
||||||
|
|
||||||
|
public void addPhone(Phone phone) {
|
||||||
|
this.phones.add( phone );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Projects {
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.PERSIST)
|
||||||
|
private Set<Project> previousProjects = new HashSet<>();
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||||
|
private Project currentProject;
|
||||||
|
|
||||||
|
public void setCurrentProject(Project project) {
|
||||||
|
this.currentProject = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPreviousProject(Project project) {
|
||||||
|
this.previousProjects.add( project );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Project> getPreviousProjects() {
|
||||||
|
return previousProjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project getCurrentProject() {
|
||||||
|
return currentProject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Project")
|
||||||
|
@Table(name = "PROJECT")
|
||||||
|
public static class Project extends AbstractEntity {
|
||||||
|
|
||||||
|
public Project() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Phone {
|
||||||
|
private String number;
|
||||||
|
|
||||||
|
public Phone() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Phone(String number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumber() {
|
||||||
|
return this.number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static class Person extends AbstractEntity {
|
||||||
|
@Embedded
|
||||||
|
private Information information;
|
||||||
|
|
||||||
|
public Information getInformation() {
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInformation(Information information) {
|
||||||
|
this.information = information;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public static class Dummy1 extends Person {
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static class Dummy2 extends Dummy1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name="Leader")
|
||||||
|
@Table(name="LEADER")
|
||||||
|
public static class Leader extends Person {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Information {
|
||||||
|
@Embedded
|
||||||
|
private ContactDetail infoContactDetail;
|
||||||
|
|
||||||
|
public ContactDetail getInfoContactDetail() {
|
||||||
|
return infoContactDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfoContactDetail(ContactDetail infoContactDetail) {
|
||||||
|
this.infoContactDetail = infoContactDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue