How to use Postgres inet data type with OpenJPA?

2019-07-15 07:35发布

问题:

I need to record IP addresses in a Postgres (9.0) table with OpenJPA (2.2.2).

I've got it working using a native query:

EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
int rows = entityManager.createNativeQuery("insert into click (ip) values (?::inet)") //
    .setParameter(1, InetAddress.getLocalHost().getHostAddress()) //
    .executeUpdate();
entityManager.getTransaction().commit();
entityManager.close();

But I'd prefer to figure out a way for OpenJPA to handle it w/o a native query.

I searched and found some other suggestions like annotating the column like this:

@Column(length = -1, columnDefinition = "inet")

But that doesn't seem to do the cast. I get this exception:

ERROR: column "ip" is of type inet but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
Position: 32 {prepstmnt 1376458920 INSERT INTO Click (ip) VALUES (?) [params=?]} [code=0, state=42804]

Can I annotate the field w/ @Strategy and implement a custom FieldStrategy or ValueHandler? This seems like the right solution, but the documentation is pretty light and I can't find a simple example to start from.

https://openjpa.apache.org/builds/2.2.2/apache-openjpa/docs/ref_guide_mapping_custom.html

Any direction on fixing the annotations or implementing a FieldStrategy or ValueHandler would be appreciated.

edit: I figured it out. Since I don't have enough rep, I can't answer my own question.

I created a custom DBDictionary that correctly does the cast.

package package.name.goes.here;
import org.apache.openjpa.jdbc.schema.Column;

public class PostgresDictionary extends org.apache.openjpa.jdbc.sql.PostgresDictionary {

@Override
public String getMarkerForInsertUpdate(Column col, Object val) {
    String colType = col.getTypeIdentifier().getName();
    if (colType != null) {
        return "?::" + colType;
    }
    return "?";
}

}

Then simply annotate the field with:

@Column(columnDefinition = "inet")

And register the custom dictionary in persistence.xml:

<property name="openjpa.jdbc.DBDictionary" value="package.name.goes.here.PostgresDictionary"/>