-1

i have 2D double array attribute but as JPA doesn't work with array i have a @XmlJavaTypeAdapter(DoubleArrayAdapter.class) to store my array in a string for postgresql...

I am working with JDK 21 and Jakarta.

i use these maven plugin to generate Java classes & sql from xsd files.

org.hibernate.orm => hibernate-jpamodelgen 6.6.2.Final              
org.patrodyne.jvnet => hisrc-hyperjaxb-maven-plugin 2.2.1

my XSD for the array attribute is :

    <xsd:element name="speeds" type="xsd:string">
        <xsd:annotation>
            <xsd:appinfo>
                <xjc:javaType  name="double[][]" adapter="org.sailquest.model.adapter.DoubleArrayAdapter"/>
            </xsd:appinfo>
        </xsd:annotation>
    </xsd:element>

There is no XJB file.

The Java code generated is :

    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(DoubleArrayAdapter.class)
    @XmlSchemaType(name = "double")
    protected double[][] speeds;

    /**
     * Obtient la valeur de la propriété speeds.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    @Transient
    public double[][] getSpeeds() {
        return speeds;
    }
    
    /**
     * Définit la valeur de la propriété speeds.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setSpeeds(double[][] value) {
        this.speeds = value;
    }
    
    @Transient
    public boolean isSetSpeeds() {
        return (this.speeds!= null);
    }

The Java generation seems ok (the getter is transient ???) but there is an error message during generation and the column is not created during database sql generation.

The speeds column is not generated because there's an error during generation : [INFO] XJC> Xhyperjaxb-jpa: : Start Parameters NaiveInheritanceStrategy.: false MaxIdentifierLength......: null PersistenceUnitName......: null PersistenceXml...........: null Result...................: annotations RoundtripTestClassName...: null ValidateXml.: null (ignored) TargetDir................: null Verbose..................: true Debug....................: false [ERROR] XJC> Xhyperjaxb-jpa: TODO [ ...ataModel/Sail.xsd{30,49} ], getAttributeMapping: class=Sail, field=speeds; could not be annotated. It will be made transient.

And the getter is transient...

Why i have this message?

Thanks for your help!

Guillaume

2 Answers 2

0

This unit test example, named floating, from the HiSrc HyperJAXB project demonstrates how to use the hisrc-hyperjaxb-maven-plugin and -Xinject-code to generate a JAXB/JPA annotated class with a property to manage a 2D double array.

Injected Code

@jakarta.persistence.Transient
public double[][] getDoubleArray()
{
    return DoubleArrayAdapter.unmarshal(getDoubleArrayB64());
}

@jakarta.persistence.Transient
public void setDoubleArray(double[][] doubleArray)
{
    setDoubleArrayB64(DoubleArrayAdapter.marshal(doubleArray));
}

The injected code, from bindings.xjb uses this custom DoubleArrayAdapter to unmarshal/marshal the byte[] array to/from a double[][] instance. The code above is declared to be JPA transient and it does not have a JAXB annotated field; instead, it delegates binding and persistence to the doubleArrayB64 field and associated property methods.

The unit test includes these resources: schema.xsd and bindings.xjb.

The schema.xsd defines this complexType.

<xs:complexType name="floatingTypesType">
    <xs:sequence>
        <xs:element name="float"  type="xs:float"  minOccurs="0"/>
        <xs:element name="double" type="xs:double" minOccurs="0"/>
        <xs:element name="doubleArrayB64" type="xs:base64Binary"/>
    </xs:sequence>
</xs:complexType>

The complexType defines a child element, named doubleArrayB64, to bind and persist the 2D double array property. When an element's type is xs:base64Binary, the XJC generates a JAXB annotated field to manage a byte[] array and the HyperJAXB plugin generates a JPA annotated property to store the value as a @Lob, as shown below.

<xs:element name="doubleArrayB64" type="xs:base64Binary"/>

Because the XML Schema type is xs:base64Binary the contents of the byte[] contains a Base64 decoding of the XML value, in this case, a 2D double array as a delimited set of rows and columns. JAXB handles the Base64 decoding and encoding. The DoubleArrayAdapter handles the parsing of the dataset.

The hisrc-hyperjaxb-maven-plugin invokes XJC to generate the FloatingTypesType class containing these statements plus the injected code from above:

FloatingTypesType.java

...
@XmlElement(required = true)
protected byte[] doubleArrayB64;
...
@Basic
@Column(name = "DOUBLE_ARRAY_B64")
@Lob
public byte[] getDoubleArrayB64() {
    return doubleArrayB64;
}
public void setDoubleArrayB64(byte[] value)
{
    this.doubleArrayB64 = value;
}
...
(plus injected code for getDoubleArray()/setDoubleArray(...))

The example depends on these Maven artifacts.

jakarta.persistence:jakarta.persistence-api:jar:3.1.0
jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.2
org.glassfish.jaxb:jaxb-runtime:jar:4.0.5
org.hibernate.orm:hibernate-core:jar:6.4.4.Final
org.patrodyne.jvnet:hisrc-hyperjaxb-maven-plugin:jar:2.2.1
org.patrodyne.jvnet:hisrc-hyperjaxb-ejb-runtime:jar:2.2.1
org.patrodyne.jvnet:hisrc-hyperjaxb-opt-hibernate:jar:2.2.1

Addendum

With regard to the question (see comments) from ghelle, "In this case the array is in a BLOB and the access is with an OID. Is it possible to use a BYTEA for array?", I have added bindings to remove the @Lob annotation and to configure the column type to be BYTEA. I have tested this successfully with Postgres and H2. See also hibernate-6-postgres-and-bytea.

bindings.xjb

...
<jaxb:bindings node="//xs:schema" schemaLocation="schema.xsd">
    <jaxb:bindings node="xs:complexType[@name='floatingTypesType']">
        ...
        <!-- PostgreSQL or H2: Use BYTEA instead of BLOB -->
        <jaxb:bindings node="xs:sequence/xs:element[@name='doubleArrayB64']">
            <anx:removeAnnotation target="getter" class="jakarta.persistence.Lob"/>
            <hj:basic>
                <orm:column column-definition="BYTEA"/>
            </hj:basic>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>
...

Disclaimer: I am the maintainer for the HiSrc projects.

Sign up to request clarification or add additional context in comments.

4 Comments

In this case the array is in a BLOB and the access is with an OID. Is it possible to use a BYTEA for array?
I have added an addendum to this answer, see above.
Thanks for that Rick and for Hyperjaxb :-)
You're welcome, If you find this answer satisfactory, please checkmark it as accepted.
-1

Thanks for your response @Rick O'Sullivan!

In this case the array is in a BLOB and the access is with an OID.

Is it possible to use a BYTEA for array?

I have added this type in the xjb file :

<jaxb:bindings node=".//xsd:element[@name='speedsB64']"> 
    <hj:basic name="content"> 
        <orm:column column-definition="bytea" />
    </hj:basic> 
 </jaxb:bindings>

So the postgres type is bytea but i need to suppress the annotation @Lob on the getter :

@Basic
    @Column(name = "SPEEDS_B64")
    @Lob
    public byte[] getSpeedsB64() {
        return speedsB64;
    }

else i have this error :

11:56:09:687 DEBUG SQL - 
    insert 
    into
        OceanRacerSchema.SAIL
        (SPEEDS_B64, ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        OceanRacerSchema.SAIL
        (SPEEDS_B64, ID) 
    values
        (?, ?)
11:56:09:718 WARN SqlExceptionHelper - SQL Error: 0, SQLState: 42804
11:56:09:718 ERROR SqlExceptionHelper - ERREUR: la colonne « speeds_b64 » est de type bytea mais l'expression est de type bigint
  Indice : Vous devez réécrire l'expression ou lui appliquer une transformation de type.
  Position : 59
11:56:09.735 [main] ERROR org.sailquest.model.loader.JsonPolarProvider - Error saving polar : jakarta.persistence.RollbackException: Transaction marked for rollback only.

Is there an other way to use bytea and not Lob?

Thanks for your Help!

1 Comment

This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.