有没有办法降低 GWT AutoBean?
Posted
技术标签:
【中文标题】有没有办法降低 GWT AutoBean?【英文标题】:Is there a way to downcast a GWT AutoBean? 【发布时间】:2011-10-04 21:34:42 【问题描述】:我一直在使用 AutoBeans 来映射来自非 GWT-RPC Java 的 Web 服务的 JSON 数据。到目前为止,除了一个映射之外,一切都正常工作。
在服务器端,Class 有一个 Map 类型的属性,其中 MyAbstractParentObject 是大约 15 个不同子类的父类。
当我将它映射到客户端上的相应 AutoBean 接口时,我无法在解码后将 MyAbstractParentObject 向下转换为其子类型。我查看了 GWT 文档和“谷歌”以查看 AutoBeans 是否甚至具有多态支持,但无论哪种方式都无法得到答案。拦截器和类别似乎无法处理这个问题,只是它们希望存在于接口中的方法不是 getter/setter。
我试图使用 JSON 数据中的 type 字段来创建子类的实例,但 AutoBean 不允许我访问原始 JSON,即使在调试器中我可以将其视为称为“数据”的受保护字段。如果我尝试解码原始 bean,它将只有 MyAbstractParentObject 中的字段。
我能看到的唯一选择是:
-
扩展或创建我自己的 AutoBeanCodex 可以正确处理
MyAbstractParentObject 解码 JSON 时的子对象。
在 MyAbstractParentObject AutoBean 中找到获取原始 JSON 的方法
并使用它来动态创建子类的实例。
切换到其他一些 JSON-GWT 序列化框架,例如
GWTProJSONSerializer 或 piriti。
任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:我知道很久以前有人问过这个问题,但我也很难找到答案。我意识到 AutoBeans,因为它们基本上只是 JSON 的精美包装器,仍然包含您想要将其向下转换为的子对象的字段的所有数据。所以我写了一个这样的方法:
public <A, B> B cast( A sourceObject, Class<B> targetClass )
AutoBean<A> sourceBean = AutoBeanUtils.getAutoBean( sourceObject ); // Get the corresponding AutoBean.
HasSplittable splittableBean = ( HasSplittable ) sourceBean; // Implementation (if still AbstractAutoBean) supports this interface ;)
Splittable splittable = splittableBean.getSplittable().deepCopy(); // If you don't copy it, decode() tries to be clever and returns
// the original bean!
AutoBean<B> targetBean = AutoBeanCodex.decode( typeFactory, targetClass, splittable ); // Create new AutoBean of
// the target type.
return targetBean.as(); // Get the proxy for the outside world.
--如你所见,typeFactory 扩展了 AutoBeanFactory。
它对我来说已经足够好了。最棘手的一点是强制转换为 HasSplittable,因为 AutoBean 不扩展该接口,但 AbstractAutoBean(它实现 AutoBean)会 - 调用 getAutoBean() 会返回该接口的子类。
您还需要复制Splittable,否则AutoBeanCodex 会认为,“嘿,我已经为那个Splittable 准备了一个AutoBean!给你!” - 并且只是给你原件。 ;)
无论如何,您可以向下、向上...向侧面投射! :P
后期编辑:几个月后再次偶然发现这一点,我想我要对乔纳森在下面提到的事情添加一个小警告。我在此处描述的方法旨在用于自反序列化以来未修改的 AutoBean。那是因为(AFAIK)不能保证您调用的任何设置器实际上都会更新 JSON(转换所需的)。这可能没什么大不了的,因为通常当你有一个传入的 DTO 并且你想尽快将它转换为它的 real 类型时,你会使用它,然后再用它做任何其他事情。在我们的例子中,我们的 AutoBeans 甚至都没有设置器,所以这不是一个真正的问题。 ;)
投射后,您可以对生成的 bean 做任何您想做的事,毕竟它是刚从工厂出来的!
【讨论】:
我不得不用 AutoBeans 做类似的事情,但我做了一个完整的编码来从 AutoBean Splittable split = AutoBeanCodex.encode(AutoBeanUtils.getAutoBean(sourceBean)); @Jonathan 我试过AutoBeanCodex.encode()
;它适用于向上转换,但不适用于向下转换 - 很遗憾,因为它是一种简单的方法。 :) encode()
使用访问者模式遍历 bean 的属性以生成新的 Splittable
。可悲的是,源 JSON 具有无法通过该 bean 访问的属性,但需要这些属性才能“向下转换”它......并且访问者看不到它们,所以来自 encode()
的 Splittable
的 JSON 没有没有它们。 :( ...因此奇怪地直接获取Splittable
并复制它;它正确解码,因为所有信息仍然存在。
我明白你在说什么。现在在我看来,这两种技术都有它们的用例。我一直在使用上面所说的方法,因为大多数时候当我将一个 autobean 转换为另一个时,我在这样做之前已经进行了更改。所以在这种情况下,我需要完整的访问者遍历才能获得所有正确的具体信息。如果您没有进行任何更改,并且您知道没有进行任何更改,那么使用HasSplittable
之后的滑坡可能会很棒。否则,您唯一的选择是执行完整编码。除非我错过了什么.....
呸,我才注意到有人回复了。 :( 我必须承认,我不知道进行更改会如何影响基础数据。我们从来没有遇到过任何问题,因为当我们想要降低 DTO 时,我们要做的第一件事就是弄清楚什么'real' 类型是(即,哪个子类),并将其转换为那个。之后我们真的不需要担心。:)【参考方案2】:
我对 AutoBean 不是很熟悉,但您可能可以使用来自 RestyGWT 的序列化器/反序列化器。它通过使用注解来支持多态性。
文档链接: http://restygwt.fusesource.org/documentation/restygwt-user-guide.html#Polymorphic_Sub_Types
【讨论】:
以上是关于有没有办法降低 GWT AutoBean?的主要内容,如果未能解决你的问题,请参考以下文章