2009-08-06 57 views
7

我真的想喜欢仿制药,但到目前为止,他们已经胜过任何利益造成的麻烦。请告诉我我错了。铸造一个可比,然后比较

我理解增加@SuppressWarnings的必要性(“未登记”)使用无通用的框架时(春,休眠)。这一点确实降低了泛型的价值,正如要求将类传递给构造函数以避免删除的缺陷一样。然而,真正的刺总是似乎在铸造。我通常会尝试一段时间以获得正确的语法,但是放弃纯粹的尝试,添加@SuppressWarnings,并继续我的生活。

这里有一个例子:我反映了一个bean来寻找两个实例之间的差异。一些属性实现Comparable,使得(a.equals(b)== false)但(a.compareTo(b)== 0)(例如BigDecimal,Date)。在这些情况下,我希望该财产被视为相同。

MyObject original = getOriginal(); 
MyObject updated = getUpdated(); 
for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(MyObject.class)) { 
    // Assume I'm putting in the try/catch block 
    Object pOriginal = pd.getReadMethod().invoke(original, (Object[]) null); 
    Object pUpdated = pd.getReadMethod().invoke(updated, (Object[]) null); 

    boolean isPropertySame; 

    if (Comparable.class.isAssignableFrom(pOriginal.getClass())) { 
     // Type safety: The method compareTo(Object) belongs to the raw type Comparable. References to generic type Comparable<T> should be parameterized 
     isPropertySame = Comparable.class.cast(pOriginal).compareTo(Comparable.class.cast(pUpdated)) == 0; 

     // The method compareTo(capture#19-of ?) in the type Comparable<capture#19-of ?> is not applicable for the arguments (capture#21-of ? extends Comparable) 
     Comparable<?> comparable = Comparable.class.cast(pOriginal); 
     isPropertySame = comparable.compareTo(comparable.getClass().getTypeParameters()[0].getGenericDeclaration().cast(pUpdated)) == 0; 

     // Even if I get the generics right, I still get an error if pOriginal is java.sql.Timestamp and pUpdated is java.util.Date (happens all the time with Hibernate). 
     isPropertySame = (help); 

    } else { 
     isPropertySame = pOriginal.equals(pUpdated); 
    } 

    if (!isPropertySame) { 
     PropertyDelta delta = new PropertyDelta(pd, pOriginal, pUpdated); 
     dao.save(delta); 
    } 
} 

关于我可以投入(帮助)的任何想法?

+1

'Timestamp'和'Date'的问题是一个众所周知的问题:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4631234。它已经在Java 6中修复(可能也在5u6)。 – notnoop 2009-08-06 22:00:54

+0

变量“originalValue”和“updatedValue”分别应该是“pOriginal”和“pUpdated”吗? – erickson 2009-08-06 22:02:08

+0

我很高兴Timestamp/Date混淆被修复。恐怕它不能帮助我,因为我被困在1.5,但很高兴知道未来。 – 2009-08-06 22:32:39

回答

0

好了,因为我没能找到一个“纯粹”的方式来做到这一点,我一直运行到的角落的情况下(如,除了这一个事实,处理是集合性的难度),我决定让我的增量生成方法方式 dumber。我意识到我只测试9种不同类型的对象,所以我可以测试我正在比较的9个对象中的哪一个,然后投射到该对象并进行特定于对象的测试。

以这种方式实现大约需要一个小时,即使每次任何对象发生变化时都必须重新编译,但我认为即使我花费了几天的时间进行此维护,我仍然处于黑色状态。

所以,最后,我想答案是没有答案。 Java泛型以这样一种方式实现,即不可能避免偶尔抑制编译器警告并危及运行时类转换异常。

4

这在我看来就像绕了艰辛的道路。你可以有你的bean实现媲美,在这种情况下,你只需要直接对它们进行比较,或者创建一个比较 -

public class Bean implements Comparable<Bean> {...} 

    public int compareTo(Bean other){ ... } 
} 

public int compare(Bean a, Bean b){ 
    Comparator<Bean> c = new Comparator<Bean>(){ 
    public int compareTo(Bean a, Bean b){ ... } 
    public boolean equals(Object o){.. } 
}; 
    return c.compare(a, b); 
} 

我同意你说的Java泛型可以得到位,呃......错综复杂。

+0

感谢您的帮助!我很抱歉,但我过分简化了我的原始示例,以适应特定类别的比较工作。我现在更新了示例,以更准确地反映我收集每个已更改属性的增量记录的要求。您还可以想象,我需要深度扫描一个非常大的对象图来生成很多这样的delta记录。 – 2009-08-06 21:06:15

2

我不很明白这有什么错只是简单地做了以下内容:

MyObject original = getOriginal(); 
MyObject updated = getUpdated(); 
for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(MyObject.class)) { 
    // Assume I'm putting in the try/catch block 
    Object pOriginal = pd.getReadMethod().invoke(original, (Object[]) null); 
    Object pUpdated = pd.getReadMethod().invoke(updated, (Object[]) null); 

    boolean isPropertySame; 
    if (pOriginal instanceof Comparable) { 
     @SuppressWarnings("unchecked") 
     Comparable<Object> originalValue = (Comparable<Object>) pOriginal; 
     @SuppressWarnings("unchecked") 
     Comparable<Object> updatedValue = (Comparable<Object>) pUpdated; 
     isPropertySame = originalValue.compareTo(updatedValue) == 0; 
    } else { 
     isPropertySame = pOriginal.equals(pUpdated); 
    } 

    if (!isPropertySame) { 
     PropertyDelta delta = new PropertyDelta(pd, pOriginal, pUpdated); 
     dao.save(delta); 
    } 
} 

在你的情况下使用Class.cast真的不类型安全帮助的。

+0

我试图避免做到这一点,因为它会引发一个警告:“可比较的是原始类型。参考泛型类型可比较的应该参数化”。现在,我可以在我的方法的顶部添加一个@SuppressWarnings,使其消失,但我希望得到一个“纯粹”的答案。该解决方案完全避免了泛型。 尽管你对cast()的用法绝对正确。它与你的解决方案中的铸造一样脆弱。它存在的唯一原因是因为我试图执行运行时类型反射/操纵。 – 2009-08-06 22:03:53

+0

鉴于泛型在运行时被删除,通用对你根本没有帮助。我只是修改了代码,使代码更“通用”。编码的可读性比满足编译器更重要,因为它不会给你带来任何额外的类型安全性。 – notnoop 2009-08-06 22:34:42

+0

在运行时是不是可以内省类型参数(即可比较的中的“X”)?我以为你可以做类似:similar.getClass()。getTypeParameters()[0] .getGenericDeclaration()。漂亮?当然不。鉴于此方法中的所有代码都是用Java1.5编写的,我认为可以编写一些不会引发任何警告/错误的内容,并且是类型安全的,而不必禁用任何内容。这是一个梦想吗? – 2009-08-09 03:18:53

1

它看起来像假设是,如果一个类实现Comparable,类型参数是类本身。那就是“class X implements Comparable<X>”。如果是这样的话,那么它是有道理的说,

X a = new X(1), b = new X(2); 
a.compareTo(b); 

但是,这绝对是可以定义,如“class X implements Comparable<Y>”一类。然后人们可以尝试这样的东西......

X a = new X(1), b = new X(2); 
a.compareTo((Y) b); 

&hellip;但很明显,将会产生ClassCastException,因为b不是Y的实例。

所以,警告是有效的。使用原始类型的代码不是类型安全的,并且可能在运行时引发异常。

+0

这里的问题是,直到运行时才知道Bean属性类型。您无法以任何方便的方式知道“Comparable”的类型参数。 – notnoop 2009-08-07 01:47:57

+0

@erickson我完全同意你的分析。但是,不应该有办法在运行时实现正确的转换 - 以便我可以测试两个对象是否可以相互比较,然后执行比较?鉴于所有可用的运行时方法,似乎你应该可以做到这一点...... – 2009-08-09 03:22:42