@ObjectTypeConverter注解重名冲突问题及转换器复用方案咨询
我在其中一个模型里定义了@ObjectTypeConverter转换器,代码如下:
@Column(name = "ACTIVE", nullable = false) @ObjectTypeConverter(name = "shortToBooleanConverter", dataType = java.lang.Short.class, objectType = java.lang.Boolean.class, defaultObjectValue = "TRUE", conversionValues = { @ConversionValue(dataValue = "0", objectValue = "False"), @ConversionValue(dataValue = "1", objectValue = "True") }) private boolean active;
在另一个模型里也做了类似定义:
@Column(name = "ACTIVE_COLLECTION", nullable = false) @ObjectTypeConverter(name = "shortToBooleanConverter", dataType = java.lang.Short.class, objectType = java.lang.Boolean.class, defaultObjectValue = "TRUE", conversionValues = { @ConversionValue(dataValue = "0", objectValue = "False"), @ConversionValue(dataValue = "1", objectValue = "True") }) private boolean activeCollection;
有些情况下,同一个模型里的多个变量也需要用到这个相同的转换逻辑。
但运行时我遇到了如下错误:
Exception Description: Conflicting annotations with the same name [shortToBooleanConverter] were found. The first one [@org.eclipse.persistence.annotations.ObjectTypeConverter({dataType=java.lang.Short, name=shortToBooleanConverter, conversionValues=[Ljava.lang.Object;@6052474f, objectType=java.lang.Boolean})] was found within [field stillConnected] and the second [@org.eclipse.persistence.annotations.ObjectTypeConverter({defaultObjectValue=TRUE, dataType=java.lang.Short, name=shortToBooleanConverter, conversionValues=[Ljava.lang.Object;@6a3b8f4c, objectType=java.lang.Boolean})] was found within [field active]. Named annotations must be unique across the persistence unit.
我该怎么解决这个问题呢?我能想到的一个办法是给每个模型里的转换器设置唯一的name属性,但既然它们的转换逻辑完全一样,有没有办法只定义一次转换器,然后在多个模型里复用呢?
当然有更优雅的复用方案啦,不用每次重复写一堆相同的转换器代码。下面给你两种靠谱的解决方式:
1. 全局注册转换器(最推荐)
你可以在persistence.xml里把这个转换器全局注册好,这样整个持久化单元里的所有实体都能直接用,不用在每个字段上重复定义转换器注解。
举个配置例子:
<persistence-unit name="yourPersistenceUnit" transaction-type="RESOURCE_LOCAL"> <!-- 这里放你的实体类配置 --> <class>com.yourpackage.YourEntity</class> <class>com.yourpackage.AnotherEntity</class> <properties> <!-- 其他数据库连接等配置 --> <property name="eclipselink.converter.shortToBooleanConverter" value="org.eclipse.persistence.converters.ObjectTypeConverter"/> <property name="eclipselink.converter.shortToBooleanConverter.dataType" value="java.lang.Short"/> <property name="eclipselink.converter.shortToBooleanConverter.objectType" value="java.lang.Boolean"/> <property name="eclipselink.converter.shortToBooleanConverter.defaultObjectValue" value="TRUE"/> <property name="eclipselink.converter.shortToBooleanConverter.conversionValues" value="0=False, 1=True"/> </properties> </persistence-unit>
之后在实体的字段上,只需要简单用@Convert注解引用这个转换器的名字就行:
@Column(name = "ACTIVE", nullable = false) @Convert("shortToBooleanConverter") private boolean active;
2. 自定义转换器类复用逻辑
如果不想碰XML配置,你可以自己写个转换器类,把转换规则封装进去,之后在实体里直接引用这个类就行。
比如写个这样的自定义转换器:
public class ShortToBooleanConverter extends ObjectTypeConverter { public ShortToBooleanConverter() { setDataType(Short.class); setObjectType(Boolean.class); addConversionValue("0", Boolean.FALSE); addConversionValue("1", Boolean.TRUE); setDefaultObjectValue(Boolean.TRUE); } }
然后在实体字段上,先通过@Converter注册这个自定义类,再用@Convert引用:
@Column(name = "ACTIVE", nullable = false) @Converter(name = "shortToBooleanConverter", converterClass = ShortToBooleanConverter.class) @Convert("shortToBooleanConverter") private boolean active;
注意哦:这个转换器只需要在第一个用到的实体上注册一次就行,后面其他实体直接用@Convert("shortToBooleanConverter")就可以了,别重复注册,不然还是会有冲突~
关于你提到的临时方案
你说的给每个转换器改个唯一名字的方式,确实能解决当前的冲突,但缺点也很明显——重复代码太多,以后要是想改转换规则,比如把0对应False改成0对应True,那你得挨个改所有地方,维护起来太麻烦了,所以还是优先用上面两种复用方案比较好。
备注:内容来源于stack exchange,提问作者Alisa

