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

Richard Zowalla updated OPENJPA-3020:
-------------------------------------
    Description: 
{{@Lob}} on an attribute with a converter gets a CLOB or BLOB column chosen 
from the Java type of the attribute, not from the database type of the 
converter. With a converter to {{String}} on an attribute that is not a 
{{String}}, the column is a BLOB:

{code:java}
@Converter
public class ItemConverter implements AttributeConverter<Item, String> { ... }

@Lob
@Convert(converter = ItemConverter.class)
private Item item;          // BLOB, expected CLOB
{code}

The opposite happens for a {{String}} attribute with a converter to {{byte[]}}: 
the column is a CLOB instead of a BLOB.

The stored value has the database type of the converter, so the column type 
does not match it. On PostgreSQL the column is {{BYTEA}} instead of {{TEXT}}. 
On MySQL and MariaDB it is {{BLOB}} instead of {{TEXT}}, and on Oracle {{BLOB}} 
instead of {{CLOB}}. On Derby the insert fails:

{noformat}
XCL12: An attempt was made to put a data value of type 'java.lang.String' into 
a data value of type 'BLOB'.
{noformat}

The same happens with {{<lob/>}} in a mapping file.

Cause: {{AnnotationPersistenceMappingParser.parseLobMapping()}} and 
{{XMLPersistenceMappingParser.endFieldMapping()}} set the column type to CLOB 
for {{String}}, {{char[]}} and {{Character[]}} attributes and to BLOB 
otherwise. Both run before the converter is known. 
{{ConverterValueHandler.map()}} only gives a template column, and 
{{MappingInfo}} keeps the type of the column the parser created.

There is a second problem with converters to {{byte[]}}, with or without 
{{@Lob}}. The column java type is {{JavaTypes.ARRAY}}, so the value is read as 
an object and the converter is passed a {{java.sql.Blob}}:

{noformat}
There was an error invoking the converter ... on Java value 
org.apache.derby.impl.jdbc.EmbedBlob@...: argument type mismatch
{noformat}

Reported by Francesco Chicchiriccò while testing Apache Syncope against 
4.2.0-SNAPSHOT on PostgreSQL. Syncope 4.1 maps {{@Lob private String 
provisions}}, which gives {{TEXT}}. Syncope 4.2 maps {{@Lob @Convert(converter 
= ProvisionListConverter.class) private List<Provision> provisions}} with an 
{{AttributeConverter<List<Provision>, String>}}, which gives {{BYTEA}}. The 
{{List}} case needs OPENJPA-3017, but the cause is older: the code is the same 
on master and in 4.1.1, and a converted attribute that is not a collection has 
the same problem there.

Fix: in {{ConverterValueHandler.map()}} and {{ConverterElementHandler.map()}}, 
where the converter is known, change a CLOB or BLOB column to CLOB for a 
converter to {{String}} and to BLOB for a converter to {{byte[]}}, and read a 
{{byte[]}} database type as {{JavaSQLTypes.BYTES}}. This covers annotations, 
mapping files, overrides and auto-applied converters.

Workaround: drop {{@Lob}} and declare the column type, e.g. 
{{@Column(columnDefinition = "TEXT")}} on PostgreSQL.

  was:
{{@Lob}} on an attribute with a converter gets a CLOB or BLOB column chosen 
from the Java type of the attribute, not from the database type of the 
converter. With a converter to {{String}} on an attribute that is not a 
{{String}}, the column is a BLOB:

{code:java}
@Converter
public class ItemConverter implements AttributeConverter<Item, String> { ... }

@Lob
@Convert(converter = ItemConverter.class)
private Item item;          // BLOB, expected CLOB
{code}

The opposite happens for a {{String}} attribute with a converter to {{byte[]}}: 
the column is a CLOB instead of a BLOB.

The stored value has the database type of the converter, so the column type 
does not match it. On PostgreSQL the column is {{BYTEA}} instead of {{TEXT}}. 
On MySQL and MariaDB it is {{BLOB}} instead of {{TEXT}}, and on Oracle {{BLOB}} 
instead of {{CLOB}}. On Derby the insert fails:

{noformat}
XCL12: An attempt was made to put a data value of type 'java.lang.String' into 
a data value of type 'BLOB'.
{noformat}

The same happens with {{<lob/>}} in a mapping file.

Cause: {{AnnotationPersistenceMappingParser.parseLobMapping()}} and 
{{XMLPersistenceMappingParser.endFieldMapping()}} set the column type to CLOB 
for {{String}}, {{char[]}} and {{Character[]}} attributes and to BLOB 
otherwise. Both run before the converter is known. 
{{ConverterValueHandler.map()}} only gives a template column, and 
{{MappingInfo}} keeps the type of the column the parser created.

There is a second problem with converters to {{byte[]}}, with or without 
{{@Lob}}. The column java type is {{JavaTypes.ARRAY}}, so the value is read as 
an object and the converter is passed a {{java.sql.Blob}}:

{noformat}
There was an error invoking the converter ... on Java value 
org.apache.derby.impl.jdbc.EmbedBlob@...: argument type mismatch
{noformat}

Reported by Francesco Chicchiriccò while testing Apache Syncope against 
4.2.0-SNAPSHOT on PostgreSQL. Syncope 4.1 maps {{@Lob private String 
provisions}}, which gives {{TEXT}}. Syncope 4.2 maps {{@Lob @Convert(converter 
= ProvisionListConverter.class) private List<Provision> provisions}} with an 
{{AttributeConverter<List<Provision>, String>}}, which gives {{BYTEA}}. The 
{{List}} case needs OPENJPA-3017, but the cause is older: the code is the same 
on master and in 4.1.1, and a converted attribute that is not a collection has 
the same problem there.

Fix: in {{ConverterValueHandler.map()}} and {{ConverterElementHandler.map()}}, 
where the converter is known, change a CLOB or BLOB column to CLOB for a 
converter to {{String}} and to BLOB for a converter to {{byte[]}}, and read a 
{{byte[]}} database type as {{JavaSQLTypes.BYTES}}. This covers annotations, 
mapping files, overrides and auto-applied converters.

Workaround: drop {{@Lob}} and declare the column type, e.g. 
{{@Column(columnDefinition = "TEXT")}} on PostgreSQL (needs OPENJPA-3018 to 
avoid a length being appended there).


> @Lob with an AttributeConverter uses the attribute type instead of the 
> converter database type
> ----------------------------------------------------------------------------------------------
>
>                 Key: OPENJPA-3020
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-3020
>             Project: OpenJPA
>          Issue Type: Bug
>    Affects Versions: 4.1.1
>            Reporter: Richard Zowalla
>            Assignee: Richard Zowalla
>            Priority: Major
>
> {{@Lob}} on an attribute with a converter gets a CLOB or BLOB column chosen 
> from the Java type of the attribute, not from the database type of the 
> converter. With a converter to {{String}} on an attribute that is not a 
> {{String}}, the column is a BLOB:
> {code:java}
> @Converter
> public class ItemConverter implements AttributeConverter<Item, String> { ... }
> @Lob
> @Convert(converter = ItemConverter.class)
> private Item item;          // BLOB, expected CLOB
> {code}
> The opposite happens for a {{String}} attribute with a converter to 
> {{byte[]}}: the column is a CLOB instead of a BLOB.
> The stored value has the database type of the converter, so the column type 
> does not match it. On PostgreSQL the column is {{BYTEA}} instead of {{TEXT}}. 
> On MySQL and MariaDB it is {{BLOB}} instead of {{TEXT}}, and on Oracle 
> {{BLOB}} instead of {{CLOB}}. On Derby the insert fails:
> {noformat}
> XCL12: An attempt was made to put a data value of type 'java.lang.String' 
> into a data value of type 'BLOB'.
> {noformat}
> The same happens with {{<lob/>}} in a mapping file.
> Cause: {{AnnotationPersistenceMappingParser.parseLobMapping()}} and 
> {{XMLPersistenceMappingParser.endFieldMapping()}} set the column type to CLOB 
> for {{String}}, {{char[]}} and {{Character[]}} attributes and to BLOB 
> otherwise. Both run before the converter is known. 
> {{ConverterValueHandler.map()}} only gives a template column, and 
> {{MappingInfo}} keeps the type of the column the parser created.
> There is a second problem with converters to {{byte[]}}, with or without 
> {{@Lob}}. The column java type is {{JavaTypes.ARRAY}}, so the value is read 
> as an object and the converter is passed a {{java.sql.Blob}}:
> {noformat}
> There was an error invoking the converter ... on Java value 
> org.apache.derby.impl.jdbc.EmbedBlob@...: argument type mismatch
> {noformat}
> Reported by Francesco Chicchiriccò while testing Apache Syncope against 
> 4.2.0-SNAPSHOT on PostgreSQL. Syncope 4.1 maps {{@Lob private String 
> provisions}}, which gives {{TEXT}}. Syncope 4.2 maps {{@Lob 
> @Convert(converter = ProvisionListConverter.class) private List<Provision> 
> provisions}} with an {{AttributeConverter<List<Provision>, String>}}, which 
> gives {{BYTEA}}. The {{List}} case needs OPENJPA-3017, but the cause is 
> older: the code is the same on master and in 4.1.1, and a converted attribute 
> that is not a collection has the same problem there.
> Fix: in {{ConverterValueHandler.map()}} and 
> {{ConverterElementHandler.map()}}, where the converter is known, change a 
> CLOB or BLOB column to CLOB for a converter to {{String}} and to BLOB for a 
> converter to {{byte[]}}, and read a {{byte[]}} database type as 
> {{JavaSQLTypes.BYTES}}. This covers annotations, mapping files, overrides and 
> auto-applied converters.
> Workaround: drop {{@Lob}} and declare the column type, e.g. 
> {{@Column(columnDefinition = "TEXT")}} on PostgreSQL.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to