[ 
https://issues.apache.org/jira/browse/OPENJPA-3017?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Richard Zowalla updated OPENJPA-3017:
-------------------------------------
    Description: 
An {{@Convert}} annotation on a collection-valued attribute is not honoured, 
and the attribute is silently excluded from the mapping. Neither an exception 
nor an error is raised, and the data is lost without notice.

Reduced case: an entity declaring

{code:java}
@Convert(converter = ItemListConverter.class)
private List<Item> items = new ArrayList<>();
{code}

where {{ItemListConverter}} implements {{AttributeConverter<List<Item>, 
String>}} and {{Item}} is a plain bean. Observed behaviour on 4.2.0-SNAPSHOT 
with Derby:

* {{ClassMapping.getField("items")}} returns {{null}}, so the field is not a 
managed field at all;
* no column is generated for it;
* a {{persist()}} followed by a {{find()}} in a fresh context returns an empty 
list, with no exception at any point;
* the sole trace is one warning stating that the field is "not a default 
persistent type, and do not have any annotations indicating their persistence 
strategy", from which it follows that {{@Convert}} is not counted as an 
indication of a persistence strategy. In a run of the full test suite several 
hundred such warnings are emitted, so the one that matters is easily missed.

Two defects follow. First, {{@Convert}} should be recognised as declaring a 
persistence strategy. Second, where the conversion cannot be applied, the 
attribute must not be dropped in silence; an error naming the attribute and the 
reason is required.

On the specified semantics: {{@Convert}} applied to a collection attribute 
other than a {{Map}}, with no {{attributeName}}, converts the *elements* of the 
collection, which would require {{AttributeConverter<Item, ?>}} together with 
{{@ElementCollection}}. A converter whose attribute type is the collection 
itself, mapping the whole collection to a single column, is a provider 
extension; Hibernate admits it. Whichever reading is implemented, the present 
behaviour is wrong, because an unsupported mapping is accepted and then ignored.

Reported on the development list by Francesco Chicchiriccò while testing Apache 
Syncope master against 4.2.0-SNAPSHOT. In that configuration the attribute is 
managed and the failure is instead

{noformat}
org.apache.openjpa.util.MetaDataException: You have supplied columns for
"...JPARealm.plainAttrs<element:class ...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)
{noformat}

which arises because the handler derived from the converter is installed and 
the element mapping is then found to carry columns. That path did not reproduce 
from the annotations alone, neither with a {{Serializable}} element type nor 
with a non-final field, and the configuration difference is still to be 
established. The message is in any case opaque with respect to the cause.

A workaround exists and was verified: the converted form serves as the 
persistent attribute, that is a {{String}} column holding the serialised value, 
the collection is marked {{@Transient}}, and the two directions are carried out 
in {{@PrePersist}}/{{@PreUpdate}} and {{@PostLoad}}. The OpenJPA extensions 
{{@Externalizer}} and {{@Factory}} offer no alternative, as {{@Persistent}} 
rejects a field of {{List}} type.


  was:
An {{@Convert}} annotation on a collection\-valued attribute is not honoured, 
and the attribute is silently excluded from the mapping. Neither an exception 
nor an error is raised, and the data is lost without notice.

Reduced case: an entity declaring

{code:java}
@Convert\(converter = ItemListConverter.class\)
private List items = new ArrayList<>\(\);
{code}

where {{ItemListConverter}} implements {{AttributeConverter, String>}} and 
{{Item}} is a plain bean. Observed behaviour on 4.2.0\-SNAPSHOT with Derby:* 
{{ClassMapping.getField\("items"\)}} returns {{null}}, so the field is not a 
managed field at all;
* no column is generated for it;
* a {{persist\(\)}} followed by a {{find\(\)}} in a fresh context returns an 
empty list, with no exception at any point;
* the sole trace is one warning stating that the field is "not a default 
persistent type, and do not have any annotations indicating their persistence 
strategy", from which it follows that {{@Convert}} is not counted as an 
indication of a persistence strategy. In a run of the full test suite several 
hundred such warnings are emitted, so the one that matters is easily missed.

Two defects follow. First, {{@Convert}} should be recognised as declaring a 
persistence strategy. Second, where the conversion cannot be applied, the 
attribute must not be dropped in silence; an error naming the attribute and the 
reason is required.

On the specified semantics: {{@Convert}} applied to a collection attribute 
other than a {{Map}}, with no {{attributeName}}, converts the _elements_ of the 
collection, which would require {{AttributeConverter}} together with 
{{@ElementCollection}}. A converter whose attribute type is the collection 
itself, mapping the whole collection to a single column, is a provider 
extension; Hibernate admits it. Whichever reading is implemented, the present 
behaviour is wrong, because an unsupported mapping is accepted and then ignored.

Reported on the development list by Francesco Chicchiriccò while testing Apache 
Syncope master against 4.2.0\-SNAPSHOT. In that configuration the attribute is 
managed and the failure is instead

{noformat}
org.apache.openjpa.util.MetaDataException: You have supplied columns for
"...JPARealm.plainAttrs", 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\)
{noformat}

which arises because the handler derived from the converter is installed and 
the element mapping is then found to carry columns. That path did not reproduce 
from the annotations alone, neither with a {{Serializable}} element type nor 
with a non\-final field, and the configuration difference is still to be 
established. The message is in any case opaque with respect to the cause.

A workaround exists and was verified: the converted form serves as the 
persistent attribute, that is a {{String}} column holding the serialised value, 
the collection is marked {{@Transient}}, and the two directions are carried out 
in {{@PrePersist}}/{{@PreUpdate}} and {{@PostLoad}}. The OpenJPA extensions 
{{@Externalizer}} and {{@Factory}} offer no alternative, as {{@Persistent}} 
rejects a field of {{List}} type.




> @Convert on a collection attribute is ignored and the attribute is silently 
> not persisted
> -----------------------------------------------------------------------------------------
>
>                 Key: OPENJPA-3017
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-3017
>             Project: OpenJPA
>          Issue Type: Bug
>    Affects Versions: 4.1.1
>            Reporter: Richard Zowalla
>            Assignee: Richard Zowalla
>            Priority: Major
>
> An {{@Convert}} annotation on a collection-valued attribute is not honoured, 
> and the attribute is silently excluded from the mapping. Neither an exception 
> nor an error is raised, and the data is lost without notice.
> Reduced case: an entity declaring
> {code:java}
> @Convert(converter = ItemListConverter.class)
> private List<Item> items = new ArrayList<>();
> {code}
> where {{ItemListConverter}} implements {{AttributeConverter<List<Item>, 
> String>}} and {{Item}} is a plain bean. Observed behaviour on 4.2.0-SNAPSHOT 
> with Derby:
> * {{ClassMapping.getField("items")}} returns {{null}}, so the field is not a 
> managed field at all;
> * no column is generated for it;
> * a {{persist()}} followed by a {{find()}} in a fresh context returns an 
> empty list, with no exception at any point;
> * the sole trace is one warning stating that the field is "not a default 
> persistent type, and do not have any annotations indicating their persistence 
> strategy", from which it follows that {{@Convert}} is not counted as an 
> indication of a persistence strategy. In a run of the full test suite several 
> hundred such warnings are emitted, so the one that matters is easily missed.
> Two defects follow. First, {{@Convert}} should be recognised as declaring a 
> persistence strategy. Second, where the conversion cannot be applied, the 
> attribute must not be dropped in silence; an error naming the attribute and 
> the reason is required.
> On the specified semantics: {{@Convert}} applied to a collection attribute 
> other than a {{Map}}, with no {{attributeName}}, converts the *elements* of 
> the collection, which would require {{AttributeConverter<Item, ?>}} together 
> with {{@ElementCollection}}. A converter whose attribute type is the 
> collection itself, mapping the whole collection to a single column, is a 
> provider extension; Hibernate admits it. Whichever reading is implemented, 
> the present behaviour is wrong, because an unsupported mapping is accepted 
> and then ignored.
> Reported on the development list by Francesco Chicchiriccò while testing 
> Apache Syncope master against 4.2.0-SNAPSHOT. In that configuration the 
> attribute is managed and the failure is instead
> {noformat}
> org.apache.openjpa.util.MetaDataException: You have supplied columns for
> "...JPARealm.plainAttrs<element:class ...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)
> {noformat}
> which arises because the handler derived from the converter is installed and 
> the element mapping is then found to carry columns. That path did not 
> reproduce from the annotations alone, neither with a {{Serializable}} element 
> type nor with a non-final field, and the configuration difference is still to 
> be established. The message is in any case opaque with respect to the cause.
> A workaround exists and was verified: the converted form serves as the 
> persistent attribute, that is a {{String}} column holding the serialised 
> value, the collection is marked {{@Transient}}, and the two directions are 
> carried out in {{@PrePersist}}/{{@PreUpdate}} and {{@PostLoad}}. The OpenJPA 
> extensions {{@Externalizer}} and {{@Factory}} offer no alternative, as 
> {{@Persistent}} rejects a field of {{List}} type.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to