问题
I want to use the PostgreSQL uuid type for objects' primary keys. For that I've created a converter (implementing the Converter interface). Bellow is the relevant code:
@Override
public void initialize(DatabaseMapping mapping, Session session) {
final DatabaseField field;
if (mapping instanceof DirectCollectionMapping) {
field = ((DirectCollectionMapping) mapping).getDirectField();
} else {
field = mapping.getField();
}
field.setSqlType(Types.OTHER);
field.setTypeName("uuid");
field.setColumnDefinition("UUID");
}
Then I've annotated the relevant entity X with the bellow annotations:
@Converter(name="uuidConverter",converterCalss=UUIDConverter.class)
@Convert("uuidConverter")
@Id
public UUID getId()
{
return id;
}
The problem is that I have another class (Y) which has the following definition:
@ManyToOne(targetEntity = X.class)
@JoinColumn(name = "x_id")
public X getX();
Although EclipseLink created the tables as expected it sends a string to the database when trying to insert objects of type Y. Postgres returns the following error message:
column "id" is of type uuid but expression is of type character varying at character
Any solutions / work around will be appreciated.
回答1:
I had the same issue with EclipseLink JPA + Postgresql + UUID as primary key.
To solve it, I've merged codes from Github and below link: https://forums.oracle.com/forums/thread.jspa?messageID=4584157
The below code for UUIDConverter worked for me, though the code surely isn't the best.
public void initialize(DatabaseMapping ARGMapping, Session ARGSession)
{
final DatabaseField Field;
if (ARGMapping instanceof DirectCollectionMapping)
{
Field = ((DirectCollectionMapping) ARGMapping).getDirectField();
}
else
{
Field = ARGMapping.getField();
}
Field.setSqlType(Types.OTHER);
Field.setTypeName("uuid");
Field.setColumnDefinition("UUID");
for (DatabaseMapping m : ARGMapping.getDescriptor().getMappings())
{
assert OneToOneMapping.class.isAssignableFrom(ManyToOneMapping.class);
if (m instanceof OneToOneMapping)
{
for (DatabaseField field : ((OneToOneMapping) m).getForeignKeyFields())
{
field.setSqlType(Types.OTHER);
field.setColumnDefinition("UUID");
field.setTypeName("uuid");
}
}
}
}
回答2:
Try checking what the fieldClassification of the mapping is in the initialize method. It might be getting String.class somehow, try setting it to Object.class.
or, field.setType(Object.class)
回答3:
I had some issues with EclipseLink JPA 2.1 + Postgresql + UUID as primary key but I find out different solution. I adopted AttributeConverter but I faced a problem with EclipseLink implementation that I resolved with this code:
@javax.persistence.Converter(autoApply = true)
public class PostgresUuidConverter implements AttributeConverter<UUID, Object> {
@Override
public Object convertToDatabaseColumn(UUID uuid) {
PostgresUuid object = new PostgresUuid();
object.setType("uuid");
try {
if (uuid == null) {
object.setValue(null);
} else {
object.setValue(uuid.toString());
}
} catch (SQLException e) {
throw new IllegalArgumentException("Error when creating Postgres uuid", e);
}
return object;
}
@Override
public UUID convertToEntityAttribute(Object dbData) {
if (dbData instanceof String) {
return UUID.fromString(dbData.toString());
} else {
return (UUID) dbData;
}
}
}
public class PostgresUuid extends PGobject implements Comparable<Object> {
private static final long serialVersionUID = 1L;
@Override
public int compareTo(Object arg0) {
return 0;
}
}
As I exaplined in detail in this post http://blog-ungarida.rhcloud.com/persisting-uuid-in-postgresql-using-jpa-eclipselink/
回答4:
Universal UUIDConverter for EclipseLink (not only PostgreSQL)
Code:
import java.nio.ByteBuffer;
import java.util.UUID;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectCollectionMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.sessions.Session;
public class UUIDConverter implements Converter {
private Boolean isUUIDasByteArray = true;
@Override
public Object convertObjectValueToDataValue(Object objectValue,
Session session) {
if (isUUIDasByteArray) {
UUID uuid = (UUID)objectValue;
if (uuid == null) return null;
byte[] buffer = new byte[16];
ByteBuffer bb = ByteBuffer.wrap(buffer);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return buffer;
}
return objectValue;
}
@Override
public UUID convertDataValueToObjectValue(Object dataValue,
Session session) {
if (isUUIDasByteArray) {
byte[] bytes = (byte[])dataValue;
if (bytes == null) return null;
ByteBuffer bb = ByteBuffer.wrap(bytes);
long high = bb.getLong();
long low = bb.getLong();
return new UUID(high, low);
}
return (UUID) dataValue;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public void initialize(DatabaseMapping mapping, Session session) {
final DatabaseField field;
if (mapping instanceof DirectCollectionMapping) {
// handle @ElementCollection...
field = ((DirectCollectionMapping) mapping).getDirectField();
} else {
field = mapping.getField();
}
if (session != null && session.getLogin()!= null && session.getLogin().getPlatform() != null) {
String platform = session.getLogin().getPlatform().getClass().getSimpleName();
if (platform.equals("PostgreSQLPlatform")) {
field.setSqlType(java.sql.Types.OTHER);
field.setTypeName("java.util.UUID");
field.setColumnDefinition("UUID");
isUUIDasByteArray = false;
} else if (platform.equals("H2Platform")) {
field.setColumnDefinition("UUID");
} else if (platform.equals("OraclePlatform")) {
field.setColumnDefinition("RAW(16)");
} else if (platform.equals("MySQLPlatform")) {
field.setColumnDefinition("BINARY(16)");
} else if (platform.equals("SQLServerPlatform")) {
field.setColumnDefinition("UNIQUEIDENTIFIER");
}
}
}
}
回答5:
You don't need a converted. Use this column definition in the entity. You need to register the uuid extension first. This works with Postgres 10 and Wildfly 10.1
@Column(name = "UUID", nullable=false, insertable = false, columnDefinition="uuid DEFAULT uuid_generate_v4()")
private String uuid;
来源:https://stackoverflow.com/questions/13346089/using-uuid-with-eclipselink-and-postgresql