我尝试在Play Framework 2.5.0中使用带有Hibernate / JPA的postgres自定义枚举。
所以基本上我添加了一个自定义UserType并添加了一个指向特定java类型/转换器的@Type注释。另外,我尝试使用JPA 2.1 @Convert和@Converter注释。我对@Enumerated和@Type( org.hibernate.type.EnumType )注释做了同样的事情。但是,任何一个对我都不起作用!
似乎注释没有重新组合,因为在printstacktrace中我看不到转换和类型类。
SQL代码
CREATE TYPE auth_service_provider AS ENUM ('faceboook', 'google', 'linkedin', 'twitter');
CREATE TABLE "auth"(
...
"auth_service" auth_service_provider NOT NULL,
"auth_username" VARCHAR(128) NOT NULL,
...
);
认证实体
@Entity
@Table(name = "auth", schema = "public", uniqueConstraints = @UniqueConstraint(columnNames = { "auth_id","user_refid" }) )
public class Auth implements java.io.Serializable {
public static enum AuthServiceProvider {
@JsonProperty("google") google,
@JsonProperty("twitter") twitter,
@JsonProperty("facebook") facebook,
@JsonProperty("linkedin") linkedin;
};
@Convert(converter = AuthServiceConverter.class)
//@Type(type="AuthServiceType")
//@Enumerated(EnumType.STRING)
//@Type(type = "org.hibernate.type.EnumType",
//parameters = {
// @Parameter(name = "enumClass", value = "AuthServiceType"),
// @Parameter(name = "type", value = "1111"),
// @Parameter(name = "useNamed", value = "true")
//})
private AuthServiceProvider authService;
private String authUsername;
...
//getters and setters
}
AuthServiceType
public class AuthServiceType implements UserType,Serializable {
private static final long serialVersionUID = 4378790812145778372L;
private static final int[] SQL_TYPES = new int[]{Types.OTHER};
@Override
public int[] sqlTypes() {
return SQL_TYPES;
}
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return deepCopy(cached);
}
@Override
public Object deepCopy(Object value) throws HibernateException {
if (value == null) return value;
try {
return AuthServiceProvider.valueOf(((AuthServiceProvider)value).name());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return ((AuthServiceProvider)value).toString();
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
if(x == y)
return true;
if(x == null || y == null)
return false;
return ((AuthServiceProvider) x).name() == ((AuthServiceProvider) y).name();
}
@Override
public int hashCode(Object value) throws HibernateException {
return ((AuthServiceProvider)value).toString().hashCode();
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Logger.debug("nullSafeGet: name {}",names[0]);
if (rs.wasNull()) {
return null;
}
Object identifier = rs.getObject(names[0]);
if (identifier instanceof PGobject) {eturn getValueOfMethod().invoke(getMappedClass(), new Object[] { (PGobject) identifier).getValue() });
return AuthServiceProvider.valueOf(((PGobject) identifier).getValue());
} else {
throw new IllegalArgumentException("AuthServiceType expected PGobject, received " + identifier.getClass().getName() + " with value of '" + identifier + "'");
}
}
@Override
public void nullSafeSet(PreparedStatement stmt, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
Logger.debug("nullSafeSet: value {}",value);
if (value == null) {
stmt.setNull(index, SQL_TYPES[0]);
} else {
PGobject pg = new PGobject();
pg.setType("auth_service_provider");
try {
pg.setValue( value.toString() );
} catch (SQLException e) {
throw new IllegalArgumentException("Value not expected for PGobject: "+value.toString(),e);
}
stmt.setObject(index, pg,SQL_TYPES[0]);
}
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return deepCopy(original);
}
@Override
@SuppressWarnings("unchecked")
public Class returnedClass() {
return AuthServiceProvider.class;
}
}
AuthServiceConverter
@Converter
public class AuthServiceConverter implements AttributeConverter<AuthServiceProvider,PGobject> {
@Override
public PGobject convertToDatabaseColumn(AuthServiceProvider value) {
Logger.debug("convertToDatabase");
PGobject pg = new PGobject();
pg.setType("auth_service_provider");
try {
pg.setValue( value.toString() );
} catch (SQLException e) {
throw new IllegalArgumentException("Value not expected for PGobject: "+value.toString(),e);
}
return pg;
}
@Override
public AuthServiceProvider convertToEntityAttribute(PGobject value) {
Logger.debug("convertToEntityAttribute");
return AuthServiceProvider.valueOf(value.getValue().toUpperCase());
}
}
异常
Caused by: org.postgresql.util.PSQLException: ERROR: column "auth_service" is of type auth_service_provider but expression is of type integer
Hint: You will need to rewrite or cast the expression.
Position: 134
修改
我发现了错误。我在字段声明中有@Type注释,在getter方法中有@Column注释。 EnumType和Converts不起作用,但Hibernate @Type 注释有效,因此注释应该在我的getter方法中与 @Column 注释一起编写。
实施例
@Column(name = "auth_service", nullable = false)
@Type(type="AuthServiceType")
public AuthServiceProvider getAuthService() {
return this.authService;
}
答案 0 :(得分:1)
尝试
@Column(columnDefinition="auth_service_provider")
@ColumnTransformer(read="auth_service::varchar", write="?::auth_service_provider")
@Enumerated(EnumType.STRING)
private AuthServiceProvider authService;