We're updating the issue view to help you get more done. 

The JPA Metamodel does not allow to retrieve the actual EmbeddableType since all instances are registered by the associated Java type

Description

Hello,

It is possible to get a FALSE executing something like this:

1 2 3 4 5 // this always returns true emf.getMetamodel().getEmbeddables().contains(Company_.address.getElementType()); // this always returns false emf.getMetamodel().getEmbeddables().contains(Person_.address.getElementType());

where Address is an @Embeddable.

The problem is here:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 // org.hibernate.metamodel.internal.AttributeFactory.class private <Y> Type<Y> getMetaModelType(ValueContext typeContext) { switch ( typeContext.getValueClassification() ) { case BASIC: { return new BasicTypeImpl<Y>( typeContext.getBindableType(), Type.PersistenceType.BASIC ); } case ENTITY: { final org.hibernate.type.EntityType type = (EntityType) typeContext.getValue().getType(); return (Type<Y>) context.locateEntityType( type.getAssociatedEntityName() ); } case EMBEDDABLE: { final Component component = (Component) typeContext.getValue(); Class javaType; if ( component.getComponentClassName() == null ) { javaType = typeContext.getBindableType(); } else { javaType = component.getComponentClass(); } ---->HERE final EmbeddableTypeImpl<Y> embeddableType = new EmbeddableTypeImpl<Y>( javaType, typeContext.getAttributeMetadata().getOwnerType(), (ComponentType) typeContext.getValue().getType() ); context.registerEmbeddedableType( embeddableType ); final Iterator<Property> subProperties = component.getPropertyIterator(); while ( subProperties.hasNext() ) { final Property property = subProperties.next(); final AttributeImplementor<Y, Object> attribute = buildAttribute( embeddableType, property ); if ( attribute != null ) { embeddableType.getBuilder().addAttribute( attribute ); } } embeddableType.lock(); return embeddableType; } default: { throw new AssertionFailure( "Unknown type : " + typeContext.getValueClassification() ); } } }

This is creating a new EmbeddableTypeImpl each time an @Embeddable is used on a different Attribute.
The problem is that EmbeddableTypeImpl (and also its class hierarchy) doesn't implement equals() so each instance is compared for equivalence as with ==.

I see 2 simple solutions:

  1. prevent the duplicated instantiation in getMetaModelType() (maybe using a Map<Class<?>, EmbeddableTypeImpl<?>>)

  2. let EmbeddableTypeImpl (maybe TypeImpl?) implement hashCode() and equals() based on getJavaType() comparison (since it is a natural unique key)

I think the problem is immediate enough to verify just looking at the code snipped, but if you need a Test Case, I'll do it asap.

If you decide to accept any of the proposed solutions, I can try to solve it and submit a PR on github.

Thank you

Environment

Wildfly 10.1.0

Status

Assignee

Vlad Mihalcea

Reporter

Michele Mariotti

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

5.3.1
5.2.12

Priority

Major