Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/atlas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
name: Hibernate ORM build-Atlas

on:
push:
branches:
- '6.2'
pull_request:
branches:
- '6.2'
Expand Down Expand Up @@ -52,7 +49,7 @@ jobs:
RUNID: ${{ github.run_number }}
run: ci/database-start.sh
- name: Set up Java 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/contributor-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
name: Hibernate ORM build

on:
push:
branches:
- '6.2'
pull_request:
branches:
- '6.2'
Expand Down Expand Up @@ -61,7 +58,7 @@ jobs:
RDBMS: ${{ matrix.rdbms }}
run: ci/database-start.sh
- name: Set up Java 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
Expand Down
6 changes: 6 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) {
currentBuild.result = 'NOT_BUILT'
return
}
// This is a limited maintenance branch, so don't run this on pushes to the branch, only on PRs
if ( !env.CHANGE_ID ) {
print "INFO: Build skipped because this job should only run for pull request, not for branch pushes"
currentBuild.result = 'NOT_BUILT'
return
}

stage('Build') {
Map<String, Closure> executions = [:]
Expand Down
6 changes: 6 additions & 0 deletions ci/jpa-3.1-tck.Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) {
currentBuild.result = 'NOT_BUILT'
return
}
// This is a limited maintenance branch, so don't run this on pushes to the branch, only on PRs
if ( !env.CHANGE_ID ) {
print "INFO: Build skipped because this job should only run for pull request, not for branch pushes"
currentBuild.result = 'NOT_BUILT'
return
}

pipeline {
agent {
Expand Down
6 changes: 6 additions & 0 deletions ci/quarkus.Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) {
currentBuild.result = 'NOT_BUILT'
return
}
// This is a limited maintenance branch, so don't run this on pushes to the branch, only on PRs
if ( !env.CHANGE_ID ) {
print "INFO: Build skipped because this job should only run for pull request, not for branch pushes"
currentBuild.result = 'NOT_BUILT'
return
}

pipeline {
agent {
Expand Down
60 changes: 0 additions & 60 deletions ci/snapshot-publish.Jenkinsfile

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.MappingModelHelper;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.model.domain.internal.AttributeContainer;
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
Expand Down Expand Up @@ -206,19 +207,45 @@ private boolean isCompatible(PersistentAttribute<?, ?> attribute1, PersistentAtt
return true;
}
final MappingMetamodel runtimeMetamodels = jpaMetamodel().getMappingMetamodel();
final EntityMappingType entity1 = runtimeMetamodels.getEntityDescriptor(
attribute1.getDeclaringType().getTypeName()
final ModelPart modelPart1 = getEntityAttributeModelPart(
attribute1,
attribute1.getDeclaringType(),
runtimeMetamodels
);
final EntityMappingType entity2 = runtimeMetamodels.getEntityDescriptor(
attribute2.getDeclaringType().getTypeName()
final ModelPart modelPart2 = getEntityAttributeModelPart(
attribute2,
attribute2.getDeclaringType(),
runtimeMetamodels
);

return entity1 != null && entity2 != null && MappingModelHelper.isCompatibleModelPart(
entity1.findSubPart( attribute1.getName() ),
entity2.findSubPart( attribute2.getName() )
return modelPart1 != null && modelPart2 != null && MappingModelHelper.isCompatibleModelPart(
modelPart1,
modelPart2
);
}

private static ModelPart getEntityAttributeModelPart(
PersistentAttribute<?, ?> attribute,
ManagedDomainType<?> domainType,
MappingMetamodel mappingMetamodel) {
if ( domainType instanceof EntityDomainType<?> ) {
final EntityMappingType entity = mappingMetamodel.getEntityDescriptor( domainType.getTypeName() );
return entity.findSubPart( attribute.getName() );
}
else {
ModelPart candidate = null;
for ( ManagedDomainType<?> subType : domainType.getSubTypes() ) {
final ModelPart modelPart = getEntityAttributeModelPart( attribute, subType, mappingMetamodel );
if ( modelPart != null ) {
if ( candidate != null && !MappingModelHelper.isCompatibleModelPart( candidate, modelPart ) ) {
return null;
}
candidate = modelPart;
}
}
return candidate;
}
}

@Override
public PersistentAttribute<? super J, ?> findAttributeInSuperTypes(String name) {
final PersistentAttribute<J, ?> local = findDeclaredAttribute( name );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* 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.orm.test.query;

import java.util.List;

import org.hibernate.testing.orm.domain.gambit.BasicEntity;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.Jira;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MappedSuperclass;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

/**
* @author Marco Belladelli
*/
@DomainModel( annotatedClasses = {
BasicEntity.class,
MappedSuperclassAttributeInMultipleSubtypesTest.BaseEntity.class,
MappedSuperclassAttributeInMultipleSubtypesTest.MappedSuper.class,
MappedSuperclassAttributeInMultipleSubtypesTest.ChildOne.class,
MappedSuperclassAttributeInMultipleSubtypesTest.ChildTwo.class,
} )
@SessionFactory
@Jira( "https://hibernate.atlassian.net/browse/HHH-17491" )
public class MappedSuperclassAttributeInMultipleSubtypesTest {
@BeforeAll
public void setUp(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final BasicEntity basicEntity = new BasicEntity( 1, "basic" );
session.persist( basicEntity );
session.persist( new ChildOne( 1L, "test", 1, basicEntity ) );
session.persist( new ChildTwo( 2L, "test", 1D, basicEntity ) );
} );
}

@AfterAll
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction( session -> {
session.createMutationQuery( "delete from BaseEntity" ).executeUpdate();
session.createMutationQuery( "delete from BasicEntity" ).executeUpdate();
} );
}

@Test
public void testSameTypeAttribute(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final List<BaseEntity> resultList = session.createQuery(
"from BaseEntity e where e.stringProp = 'test'",
BaseEntity.class
).getResultList();
assertThat( resultList ).hasSize( 2 );
assertThat( resultList.stream().map( BaseEntity::getId ) ).contains( 1L, 2L );
} );
}

@Test
public void testDifferentTypeAttribute(SessionFactoryScope scope) {
scope.inTransaction( session -> {
try {
session.createQuery(
"from BaseEntity e where e.otherProp = 1",
BaseEntity.class
).getResultList();
fail( "This shouldn't work since the attribute is defined with different types" );
}
catch (Exception e) {
final Throwable cause = e.getCause().getCause();
assertThat( cause ).isInstanceOf( IllegalArgumentException.class );
assertThat( cause.getMessage() ).contains( "Could not resolve attribute 'otherProp'" );
}
} );
}

@Test
public void testToOneAttribute(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final BasicEntity basicEntity = session.find( BasicEntity.class, 1 );
final List<BaseEntity> resultList = session.createQuery(
"from BaseEntity e where e.toOneProp = :be",
BaseEntity.class
).setParameter( "be", basicEntity ).getResultList();
assertThat( resultList ).hasSize( 2 );
assertThat( resultList.stream().map( BaseEntity::getId ) ).contains( 1L, 2L );
} );
}

@Entity( name = "BaseEntity" )
public static class BaseEntity {
@Id
private Long id;

public BaseEntity() {
}

public BaseEntity(Long id) {
this.id = id;
}

public Long getId() {
return id;
}
}

@MappedSuperclass
@SuppressWarnings( "unused" )
public static abstract class MappedSuper extends BaseEntity {
private String stringProp;

private Integer otherProp;

@ManyToOne
private BasicEntity toOneProp;

public MappedSuper() {
}

public MappedSuper(Long id, String stringProp, Integer otherProp, BasicEntity toOneProp) {
super( id );
this.stringProp = stringProp;
this.otherProp = otherProp;
this.toOneProp = toOneProp;
}
}

@Entity( name = "ChildOne" )
public static class ChildOne extends MappedSuper {
public ChildOne() {
}

public ChildOne(Long id, String stringProp, Integer otherProp, BasicEntity toOneProp) {
super( id, stringProp, otherProp, toOneProp );
}
}

@Entity( name = "ChildTwo" )
@SuppressWarnings( "unused" )
public static class ChildTwo extends BaseEntity {
private String stringProp;

private Double otherProp;

@ManyToOne
private BasicEntity toOneProp;

public ChildTwo() {
}

public ChildTwo(Long id, String stringProp, Double otherProp, BasicEntity toOneProp) {
super( id );
this.stringProp = stringProp;
this.otherProp = otherProp;
this.toOneProp = toOneProp;
}
}
}