You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openjpa.apache.org by Francesco Chicchiriccò <il...@apache.org> on 2026/10/21 10:45:43 UTC

Testing 4.2.0: AttributeConverter

Hi all,
I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.

The first error I am encountering is related to [1] e.g.

@Convert(converter = PlainAttrListConverter.class)
private final List<PlainAttr> plainAttrs = new ArrayList<>();

where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.

This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:

<openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
         at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
         at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
         at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
         at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
         at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
         at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
         at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
         at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
         at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
         at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
         at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
         at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
         at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
         at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
         at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
         at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)


Is there anything obvious I am missing?

TIA
Regards.

[1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
[2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
[3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java

-- 
Francesco Chicchiriccò

Tirasa - Open Source Excellence
http://www.tirasa.net/

Member at The Apache Software Foundation
Syncope, Cocoon, Olingo, CXF, OpenJPA
https://about.me/ilgrosso


Re: Testing 4.2.0: AttributeConverter

Posted by Richard Zowalla <rz...@apache.org>.
Will push a follow up shortly

> Am 22.10.2026 um 15:15 schrieb Francesco Chicchiriccò <il...@apache.org>:
> 
> Hum, this is not what I am seeing at
> 
> https://github.com/apache/openjpa/pull/220/changes#diff-b2a7225b359717a255a5118c3996fa15b43ba365c6b1812e3b20ccf064268b02R32
> 
> e.g.
> 
> @Converter
> public class ItemListConverter implements AttributeConverter<List<Item>, String> {
> 
> while we have
> 
> @Converter
> public class PlainAttrListConverter implements AttributeConverter<List<PlainAttr>, String> {
> 
> On 22/10/26 15:11, Maxim Solodovnik wrote:
>> I believe you still need to change your converter to have 2 generic
>> parameters AttributeConverter<PlainAttr, ?>
>> 
>> On Thu, 22 Oct 2026 at 20:06, Francesco Chicchiriccò
>> <il...@apache.org> wrote:
>>> So I went ahead, built the branch OPENJPA-3017 locally, then tried again with Syncope but... got the same identical stacktrace.
>>> 
>>> Is there any non-default setting I should apply?
>>> 
>>> Thank you.
>>> Regards.
>>> 
>>> On 22/10/26 11:28, Francesco Chicchiriccò wrote:
>>>> On 22/10/26 11:24, Maxim Solodovnik wrote:
>>>>> On Thu, 22 Oct 2026 at 16:22, Francesco Chicchiriccò
>>>>> <il...@apache.org> wrote:
>>>>>> Hi Richard,
>>>>>> I saw (and approved) your PR, thank you!
>>>>>> 
>>>>>> Related to:
>>>>>>> As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>>>>>> this is the approach we follow up to Syncope 4.1.x, which is based on OpenJPA 4.1.1.
>>>>>> 
>>>>>> Some background information.
>>>>>> A while ago we switched to Hibernate ORM because of their support for JPA 3.2 (and the license change too, of course) since it was required by the Spring Boot platform upgrade.
>>>>>> OpenJPA was not ready at that time but now, considering the recent efforts here, we are reconsidering; only, we would rather not loose the code improvements applied so far.
>>>>>> 
>>>>>> Let's see how things are going after merging your PR, fingers crossed.
>>>>> You can test from branch :)
>>>> That's also true ;-)
>>>> I cannot dedicate much time today but this is definitely something possible, maybe I'll leave it on background and report afterwards.
>>>> 
>>>>> On 21/10/26 21:48, Richard Zowalla wrote:
>>>>>>> Hi Francesco,
>>>>>>> 
>>>>>>> Nothing obvious is missing. I see 2 things:
>>>>>>> 
>>>>>>> The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.
>>>>>>> 
>>>>>>> The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.
>>>>>>> 
>>>>>>> The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>>>>>>> 
>>>>>>> Gruß
>>>>>>> Richard
>>>>>>> 
>>>>>>>> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
>>>>>>>> 
>>>>>>>> Hi all,
>>>>>>>> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
>>>>>>>> 
>>>>>>>> The first error I am encountering is related to [1] e.g.
>>>>>>>> 
>>>>>>>> @Convert(converter = PlainAttrListConverter.class)
>>>>>>>> private final List<PlainAttr> plainAttrs = new ArrayList<>();
>>>>>>>> 
>>>>>>>> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
>>>>>>>> 
>>>>>>>> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
>>>>>>>> 
>>>>>>>> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
>>>>>>>>           at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
>>>>>>>>           at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
>>>>>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
>>>>>>>>           at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
>>>>>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
>>>>>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
>>>>>>>>           at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
>>>>>>>>           at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>>>>           at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
>>>>>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
>>>>>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
>>>>>>>> 
>>>>>>>> 
>>>>>>>> Is there anything obvious I am missing?
>>>>>>>> 
>>>>>>>> TIA
>>>>>>>> Regards.
>>>>>>>> 
>>>>>>>> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
>>>>>>>> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
>>>>>>>> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java--
> 
> -- 
> Francesco Chicchiriccò
> 
> Tirasa - Open Source Excellence
> http://www.tirasa.net/
> 
> Member at The Apache Software Foundation
> Syncope, Cocoon, Olingo, CXF, OpenJPA
> https://about.me/ilgrosso


Re: Testing 4.2.0: AttributeConverter

Posted by Francesco Chicchiriccò <il...@apache.org>.
Hum, this is not what I am seeing at

https://github.com/apache/openjpa/pull/220/changes#diff-b2a7225b359717a255a5118c3996fa15b43ba365c6b1812e3b20ccf064268b02R32

e.g.

@Converter
public class ItemListConverter implements AttributeConverter<List<Item>, String> {

while we have

@Converter
public class PlainAttrListConverter implements AttributeConverter<List<PlainAttr>, String> {

On 22/10/26 15:11, Maxim Solodovnik wrote:
> I believe you still need to change your converter to have 2 generic
> parameters AttributeConverter<PlainAttr, ?>
>
> On Thu, 22 Oct 2026 at 20:06, Francesco Chicchiriccò
> <il...@apache.org> wrote:
>> So I went ahead, built the branch OPENJPA-3017 locally, then tried again with Syncope but... got the same identical stacktrace.
>>
>> Is there any non-default setting I should apply?
>>
>> Thank you.
>> Regards.
>>
>> On 22/10/26 11:28, Francesco Chicchiriccò wrote:
>>> On 22/10/26 11:24, Maxim Solodovnik wrote:
>>>> On Thu, 22 Oct 2026 at 16:22, Francesco Chicchiriccò
>>>> <il...@apache.org> wrote:
>>>>> Hi Richard,
>>>>> I saw (and approved) your PR, thank you!
>>>>>
>>>>> Related to:
>>>>>> As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>>>>> this is the approach we follow up to Syncope 4.1.x, which is based on OpenJPA 4.1.1.
>>>>>
>>>>> Some background information.
>>>>> A while ago we switched to Hibernate ORM because of their support for JPA 3.2 (and the license change too, of course) since it was required by the Spring Boot platform upgrade.
>>>>> OpenJPA was not ready at that time but now, considering the recent efforts here, we are reconsidering; only, we would rather not loose the code improvements applied so far.
>>>>>
>>>>> Let's see how things are going after merging your PR, fingers crossed.
>>>> You can test from branch :)
>>> That's also true ;-)
>>> I cannot dedicate much time today but this is definitely something possible, maybe I'll leave it on background and report afterwards.
>>>
>>>> On 21/10/26 21:48, Richard Zowalla wrote:
>>>>>> Hi Francesco,
>>>>>>
>>>>>> Nothing obvious is missing. I see 2 things:
>>>>>>
>>>>>> The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.
>>>>>>
>>>>>> The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.
>>>>>>
>>>>>> The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>>>>>>
>>>>>> Gruß
>>>>>> Richard
>>>>>>
>>>>>>> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
>>>>>>>
>>>>>>> Hi all,
>>>>>>> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
>>>>>>>
>>>>>>> The first error I am encountering is related to [1] e.g.
>>>>>>>
>>>>>>> @Convert(converter = PlainAttrListConverter.class)
>>>>>>> private final List<PlainAttr> plainAttrs = new ArrayList<>();
>>>>>>>
>>>>>>> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
>>>>>>>
>>>>>>> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
>>>>>>>
>>>>>>> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
>>>>>>>            at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
>>>>>>>            at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
>>>>>>>            at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
>>>>>>>            at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
>>>>>>>            at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
>>>>>>>            at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
>>>>>>>            at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
>>>>>>>            at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>>>>            at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>>>>            at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>>>>            at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>>>>            at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>>>>            at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>>>>            at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>>>>            at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>>>>            at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>>>            at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
>>>>>>>            at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
>>>>>>>            at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
>>>>>>>
>>>>>>>
>>>>>>> Is there anything obvious I am missing?
>>>>>>>
>>>>>>> TIA
>>>>>>> Regards.
>>>>>>>
>>>>>>> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
>>>>>>> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
>>>>>>> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java--

-- 
Francesco Chicchiriccò

Tirasa - Open Source Excellence
http://www.tirasa.net/

Member at The Apache Software Foundation
Syncope, Cocoon, Olingo, CXF, OpenJPA
https://about.me/ilgrosso


Re: Testing 4.2.0: AttributeConverter

Posted by Maxim Solodovnik <so...@gmail.com>.
I believe you still need to change your converter to have 2 generic
parameters AttributeConverter<PlainAttr, ?>

On Thu, 22 Oct 2026 at 20:06, Francesco Chicchiriccò
<il...@apache.org> wrote:
>
> So I went ahead, built the branch OPENJPA-3017 locally, then tried again with Syncope but... got the same identical stacktrace.
>
> Is there any non-default setting I should apply?
>
> Thank you.
> Regards.
>
> On 22/10/26 11:28, Francesco Chicchiriccò wrote:
> > On 22/10/26 11:24, Maxim Solodovnik wrote:
> >> On Thu, 22 Oct 2026 at 16:22, Francesco Chicchiriccò
> >> <il...@apache.org> wrote:
> >>> Hi Richard,
> >>> I saw (and approved) your PR, thank you!
> >>>
> >>> Related to:
> >>>> As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
> >>> this is the approach we follow up to Syncope 4.1.x, which is based on OpenJPA 4.1.1.
> >>>
> >>> Some background information.
> >>> A while ago we switched to Hibernate ORM because of their support for JPA 3.2 (and the license change too, of course) since it was required by the Spring Boot platform upgrade.
> >>> OpenJPA was not ready at that time but now, considering the recent efforts here, we are reconsidering; only, we would rather not loose the code improvements applied so far.
> >>>
> >>> Let's see how things are going after merging your PR, fingers crossed.
> >> You can test from branch :)
> >
> > That's also true ;-)
> > I cannot dedicate much time today but this is definitely something possible, maybe I'll leave it on background and report afterwards.
> >
> >> On 21/10/26 21:48, Richard Zowalla wrote:
> >>>> Hi Francesco,
> >>>>
> >>>> Nothing obvious is missing. I see 2 things:
> >>>>
> >>>> The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.
> >>>>
> >>>> The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.
> >>>>
> >>>> The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
> >>>>
> >>>> Gruß
> >>>> Richard
> >>>>
> >>>>> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
> >>>>>
> >>>>> Hi all,
> >>>>> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
> >>>>>
> >>>>> The first error I am encountering is related to [1] e.g.
> >>>>>
> >>>>> @Convert(converter = PlainAttrListConverter.class)
> >>>>> private final List<PlainAttr> plainAttrs = new ArrayList<>();
> >>>>>
> >>>>> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
> >>>>>
> >>>>> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
> >>>>>
> >>>>> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
> >>>>>           at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
> >>>>>           at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
> >>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
> >>>>>           at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
> >>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
> >>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
> >>>>>           at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
> >>>>>           at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
> >>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
> >>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
> >>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
> >>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
> >>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
> >>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
> >>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
> >>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
> >>>>>           at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
> >>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
> >>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
> >>>>>
> >>>>>
> >>>>> Is there anything obvious I am missing?
> >>>>>
> >>>>> TIA
> >>>>> Regards.
> >>>>>
> >>>>> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
> >>>>> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
> >>>>> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java
>
> --
> Francesco Chicchiriccò
>
> Tirasa - Open Source Excellence
> http://www.tirasa.net/
>
> Member at The Apache Software Foundation
> Syncope, Cocoon, Olingo, CXF, OpenJPA
> https://about.me/ilgrosso
>


-- 
Best regards,
Maxim

Re: Testing 4.2.0: AttributeConverter

Posted by Francesco Chicchiriccò <il...@apache.org>.
So I went ahead, built the branch OPENJPA-3017 locally, then tried again with Syncope but... got the same identical stacktrace.

Is there any non-default setting I should apply?

Thank you.
Regards.

On 22/10/26 11:28, Francesco Chicchiriccò wrote:
> On 22/10/26 11:24, Maxim Solodovnik wrote:
>> On Thu, 22 Oct 2026 at 16:22, Francesco Chicchiriccò
>> <il...@apache.org> wrote:
>>> Hi Richard,
>>> I saw (and approved) your PR, thank you!
>>>
>>> Related to:
>>>> As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>>> this is the approach we follow up to Syncope 4.1.x, which is based on OpenJPA 4.1.1.
>>>
>>> Some background information.
>>> A while ago we switched to Hibernate ORM because of their support for JPA 3.2 (and the license change too, of course) since it was required by the Spring Boot platform upgrade.
>>> OpenJPA was not ready at that time but now, considering the recent efforts here, we are reconsidering; only, we would rather not loose the code improvements applied so far.
>>>
>>> Let's see how things are going after merging your PR, fingers crossed.
>> You can test from branch :)
>
> That's also true ;-)
> I cannot dedicate much time today but this is definitely something possible, maybe I'll leave it on background and report afterwards.
>
>> On 21/10/26 21:48, Richard Zowalla wrote:
>>>> Hi Francesco,
>>>>
>>>> Nothing obvious is missing. I see 2 things:
>>>>
>>>> The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.
>>>>
>>>> The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.
>>>>
>>>> The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>>>>
>>>> Gruß
>>>> Richard
>>>>
>>>>> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
>>>>>
>>>>> Hi all,
>>>>> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
>>>>>
>>>>> The first error I am encountering is related to [1] e.g.
>>>>>
>>>>> @Convert(converter = PlainAttrListConverter.class)
>>>>> private final List<PlainAttr> plainAttrs = new ArrayList<>();
>>>>>
>>>>> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
>>>>>
>>>>> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
>>>>>
>>>>> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
>>>>>           at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
>>>>>           at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
>>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
>>>>>           at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
>>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
>>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
>>>>>           at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
>>>>>           at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>>           at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
>>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
>>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
>>>>>
>>>>>
>>>>> Is there anything obvious I am missing?
>>>>>
>>>>> TIA
>>>>> Regards.
>>>>>
>>>>> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
>>>>> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
>>>>> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java

-- 
Francesco Chicchiriccò

Tirasa - Open Source Excellence
http://www.tirasa.net/

Member at The Apache Software Foundation
Syncope, Cocoon, Olingo, CXF, OpenJPA
https://about.me/ilgrosso


Re: Testing 4.2.0: AttributeConverter

Posted by Francesco Chicchiriccò <il...@apache.org>.
On 22/10/26 11:24, Maxim Solodovnik wrote:
> On Thu, 22 Oct 2026 at 16:22, Francesco Chicchiriccò
> <il...@apache.org> wrote:
>> Hi Richard,
>> I saw (and approved) your PR, thank you!
>>
>> Related to:
>>> As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>> this is the approach we follow up to Syncope 4.1.x, which is based on OpenJPA 4.1.1.
>>
>> Some background information.
>> A while ago we switched to Hibernate ORM because of their support for JPA 3.2 (and the license change too, of course) since it was required by the Spring Boot platform upgrade.
>> OpenJPA was not ready at that time but now, considering the recent efforts here, we are reconsidering; only, we would rather not loose the code improvements applied so far.
>>
>> Let's see how things are going after merging your PR, fingers crossed.
> You can test from branch :)

That's also true ;-)
I cannot dedicate much time today but this is definitely something possible, maybe I'll leave it on background and report afterwards.

> On 21/10/26 21:48, Richard Zowalla wrote:
>>> Hi Francesco,
>>>
>>> Nothing obvious is missing. I see 2 things:
>>>
>>> The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.
>>>
>>> The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.
>>>
>>> The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>>>
>>> Gruß
>>> Richard
>>>
>>>> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
>>>>
>>>> Hi all,
>>>> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
>>>>
>>>> The first error I am encountering is related to [1] e.g.
>>>>
>>>> @Convert(converter = PlainAttrListConverter.class)
>>>> private final List<PlainAttr> plainAttrs = new ArrayList<>();
>>>>
>>>> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
>>>>
>>>> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
>>>>
>>>> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
>>>>           at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
>>>>           at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
>>>>           at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
>>>>           at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
>>>>           at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
>>>>           at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>>>           at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>>>           at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>>>           at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>>>           at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
>>>>           at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
>>>>
>>>>
>>>> Is there anything obvious I am missing?
>>>>
>>>> TIA
>>>> Regards.
>>>>
>>>> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
>>>> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
>>>> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java

-- 
Francesco Chicchiriccò

Tirasa - Open Source Excellence
http://www.tirasa.net/

Member at The Apache Software Foundation
Syncope, Cocoon, Olingo, CXF, OpenJPA
https://about.me/ilgrosso


Re: Testing 4.2.0: AttributeConverter

Posted by Maxim Solodovnik <so...@gmail.com>.
On Thu, 22 Oct 2026 at 16:22, Francesco Chicchiriccò
<il...@apache.org> wrote:
>
> Hi Richard,
> I saw (and approved) your PR, thank you!
>
> Related to:
> > As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>
> this is the approach we follow up to Syncope 4.1.x, which is based on OpenJPA 4.1.1.
>
> Some background information.
> A while ago we switched to Hibernate ORM because of their support for JPA 3.2 (and the license change too, of course) since it was required by the Spring Boot platform upgrade.
> OpenJPA was not ready at that time but now, considering the recent efforts here, we are reconsidering; only, we would rather not loose the code improvements applied so far.
>
> Let's see how things are going after merging your PR, fingers crossed.

You can test from branch :)

> Regards.
>
> On 21/10/26 21:48, Richard Zowalla wrote:
> > Hi Francesco,
> >
> > Nothing obvious is missing. I see 2 things:
> >
> > The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.
> >
> > The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.
> >
> > The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
> >
> > Gruß
> > Richard
> >
> >> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
> >>
> >> Hi all,
> >> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
> >>
> >> The first error I am encountering is related to [1] e.g.
> >>
> >> @Convert(converter = PlainAttrListConverter.class)
> >> private final List<PlainAttr> plainAttrs = new ArrayList<>();
> >>
> >> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
> >>
> >> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
> >>
> >> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
> >>          at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
> >>          at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
> >>          at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
> >>          at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
> >>          at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
> >>          at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
> >>          at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
> >>          at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
> >>          at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
> >>          at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
> >>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
> >>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
> >>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
> >>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
> >>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
> >>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
> >>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
> >>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
> >>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
> >>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
> >>          at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
> >>          at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
> >>          at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
> >>          at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
> >>          at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
> >>
> >>
> >> Is there anything obvious I am missing?
> >>
> >> TIA
> >> Regards.
> >>
> >> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
> >> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
> >> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java
> >>
> >> --
> >> Francesco Chicchiriccò
> >>
> >> Tirasa - Open Source Excellence
> >> http://www.tirasa.net/
> >>
> >> Member at The Apache Software Foundation
> >> Syncope, Cocoon, Olingo, CXF, OpenJPA
> >> https://about.me/ilgrosso
> >>
>
> --
> Francesco Chicchiriccò
>
> Tirasa - Open Source Excellence
> http://www.tirasa.net/
>
> Member at The Apache Software Foundation
> Syncope, Cocoon, Olingo, CXF, OpenJPA
> https://about.me/ilgrosso
>


-- 
Best regards,
Maxim

Re: Testing 4.2.0: AttributeConverter

Posted by Francesco Chicchiriccò <il...@apache.org>.
Hi Richard,
I saw (and approved) your PR, thank you!

Related to:
> As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?

this is the approach we follow up to Syncope 4.1.x, which is based on OpenJPA 4.1.1.

Some background information.
A while ago we switched to Hibernate ORM because of their support for JPA 3.2 (and the license change too, of course) since it was required by the Spring Boot platform upgrade.
OpenJPA was not ready at that time but now, considering the recent efforts here, we are reconsidering; only, we would rather not loose the code improvements applied so far.

Let's see how things are going after merging your PR, fingers crossed.
Regards.

On 21/10/26 21:48, Richard Zowalla wrote:
> Hi Francesco,
>
> Nothing obvious is missing. I see 2 things:
>
> The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.
>
> The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.
>
> The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?
>
> Gruß
> Richard
>
>> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
>>
>> Hi all,
>> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
>>
>> The first error I am encountering is related to [1] e.g.
>>
>> @Convert(converter = PlainAttrListConverter.class)
>> private final List<PlainAttr> plainAttrs = new ArrayList<>();
>>
>> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
>>
>> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
>>
>> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
>>          at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
>>          at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
>>          at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
>>          at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
>>          at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
>>          at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
>>          at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
>>          at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
>>          at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
>>          at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>>          at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>>          at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>>          at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>>          at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>>          at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
>>          at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
>>          at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
>>
>>
>> Is there anything obvious I am missing?
>>
>> TIA
>> Regards.
>>
>> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
>> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
>> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java
>>
>> -- 
>> Francesco Chicchiriccò
>>
>> Tirasa - Open Source Excellence
>> http://www.tirasa.net/
>>
>> Member at The Apache Software Foundation
>> Syncope, Cocoon, Olingo, CXF, OpenJPA
>> https://about.me/ilgrosso
>>

-- 
Francesco Chicchiriccò

Tirasa - Open Source Excellence
http://www.tirasa.net/

Member at The Apache Software Foundation
Syncope, Cocoon, Olingo, CXF, OpenJPA
https://about.me/ilgrosso


Re: Testing 4.2.0: AttributeConverter

Posted by Richard Zowalla <rz...@apache.org>.
Hi Francesco,

Nothing obvious is missing. I see 2 things:

The first concerns the mapping itself. @Convert applied to a collection attribute converts the elements, so List<PlainAttr> would require AttributeConverter<PlainAttr, ?> together with @ElementCollection. PlainAttrListConverter converts the collection as a whole into a single column, which Hibernate accepts but which is undefined behaviour (according to the spec), and the mapping is therefore not portable.

The second concerns a defect on our side, for which we need to fill a bug. Reduced to an entity holding a List field and a whole-collection converter, OpenJPA does not register the field at all: no column is generated, and a persist followed by a find yields an empty list without an error. The sole trace is a warning that the field has no annotation indicating a persistence strategy, from which it follows that @Convert is not treated as one. Silent loss of the attribute is a more concerning outcome, more so than the exception you observed.

The exception itself did not reproduce from those annotations alone, neither with a Serializable element type nor with a non-final field. Its origin is HandlerFieldStrategy.map, which installs the handler derived from the converter and then rejects columns supplied for the element; the field is thus managed in your configuration and unmanaged in my test setup. To check the difference  we would need to know whether plainAttrs is declared in an orm.xml, whether any @Access, @Basic or @Column reaches it by way of Attributable, Realm or an attribute override, and which openjpa.* properties the unit sets. As an interim mapping, the converted form may serve as the persistent attribute: a String column holding the JSON, the List marked @Transient, and the two directions be done in @PrePersist/@PreUpdate and @PostLoad maybe?

Gruß
Richard

> Am 21.10.2026 um 12:45 schrieb Francesco Chicchiriccò <il...@apache.org>:
> 
> Hi all,
> I am testing OpenJPA 4.2.0-SNAPSHOT against Syncope master branch, which is currently using Hibernate ORM 7.4.
> 
> The first error I am encountering is related to [1] e.g.
> 
> @Convert(converter = PlainAttrListConverter.class)
> private final List<PlainAttr> plainAttrs = new ArrayList<>();
> 
> where PlainAttr [2] is a Java bean configured for JSON serialization and PlainAttrListConverter[3] is an AttributeConverter leveraging Jackson for this purpose.
> 
> This works fine under Hibernate, but throws the following exception with OpenJPA 4.2.0-SNAPSHOT:
> 
> <openjpa-4.2.0-SNAPSHOT-ra2c8177 fatal user error> org.apache.openjpa.util.MetaDataException: You have supplied columns for "org.apache.syncope.core.persistence.jpa.entity.JPARealm.plainAttrs<element:class org.apache.syncope.core.persistence.api.entity.PlainAttr>", but this mapping cannot have columns in this context.
>         at org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:384)
>         at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.map(HandlerFieldStrategy.java:84)
>         at org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:148)
>         at org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:87)
>         at org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:519)
>         at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:470)
>         at org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:1066)
>         at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:420)
>         at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:780)
>         at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:667)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:427)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>         at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.getCachedSuperclassMetaData(PersistenceMetaDataDefaults.java:355)
>         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.determineAccessType(PersistenceMetaDataDefaults.java:381)
>         at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:317)
>         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:933)
>         at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:918)
>         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.getMetaData(AnnotationPersistenceMetaDataParser.java:828)
>         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:582)
>         at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:440)
>         at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:267)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:595)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:406)
>         at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:398)
>         at org.apache.openjpa.persistence.meta.MetamodelImpl.<init>(MetamodelImpl.java:91)
>         at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:474)
>         at org.apache.openjpa.persistence.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:81)
> 
> 
> Is there anything obvious I am missing?
> 
> TIA
> Regards.
> 
> [1] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java#L83-L84
> [2] https://github.com/apache/syncope/blob/master/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
> [3] https://github.com/apache/syncope/blob/master/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/converters/PlainAttrListConverter.java
> 
> -- 
> Francesco Chicchiriccò
> 
> Tirasa - Open Source Excellence
> http://www.tirasa.net/
> 
> Member at The Apache Software Foundation
> Syncope, Cocoon, Olingo, CXF, OpenJPA
> https://about.me/ilgrosso
>