jface databinding/PojoBindable实现对POJO对象的支持
来源:互联网 发布:java游戏高级编程 编辑:程序博客网 时间:2024/05/22 06:27
POJO对象无法被监控
在jface databinding中,将普通的java bean(有get/set方法但没有通过PropertyChangeSupport实现属性监控)定义为POJO对象。
我们可以对POJO对象通过PojoProperties.value(String propertyName)
方法提供IObservableValue实例,但返回的PojoValueProperty实例并没有真正实现对POJO对象的监控(参见PojoValueProperty源码)。
所以UI组件与POJO对象之间建立的数据绑定是单向的,UI组件的数据变化可以同步到POJO对象,但反过来不行。
下面这个示例可以演示这个区别,
运行程序,程序启动时,Text组件的内容被更新成POJO对象属性相同的值。
但按”测试”按钮,修改了POJO对象的属性,但Text控件的值并没有同步变化。
package testwb;import org.eclipse.jface.dialogs.Dialog;import org.eclipse.jface.dialogs.IDialogConstants;import org.eclipse.swt.graphics.Point;import org.eclipse.swt.widgets.Composite;import org.eclipse.swt.widgets.Control;import org.eclipse.swt.widgets.Shell;import org.eclipse.swt.SWT;import org.eclipse.swt.widgets.Text;import org.eclipse.core.databinding.DataBindingContext;import org.eclipse.core.databinding.observable.value.IObservableValue;import org.eclipse.jface.databinding.swt.WidgetProperties;import org.eclipse.swt.widgets.Display;import org.eclipse.core.databinding.observable.Realm;import org.eclipse.jface.databinding.swt.DisplayRealm;import org.eclipse.swt.widgets.Button;import org.eclipse.swt.events.SelectionAdapter;import org.eclipse.swt.events.SelectionEvent;import org.eclipse.core.databinding.beans.PojoProperties;public class TestPojoBinding extends Dialog { /** * 数据对象定义 * @author guyadong * */ public class Configuration { private String name; public Configuration(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; System.out.printf("updated %s\n",this.name); } } private DataBindingContext m_bindingContext; /** * 成员变量:数据对象 */ protected Configuration editorConfig=new Configuration("hello!"); private Text myNametext; /** * Create the dialog. * @param parentShell */ public TestPojoBinding(Shell parentShell) { super(parentShell); } /** * Create contents of the dialog. * @param parent */ @Override protected Control createDialogArea(Composite parent) { Composite container = (Composite) super.createDialogArea(parent); container.setLayout(null); Button btnNewButton = new Button(container, SWT.NONE); btnNewButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { editorConfig.setName("word"); } }); btnNewButton.setBounds(38, 154, 80, 27); btnNewButton.setText("测试"); myNametext = new Text(container, SWT.BORDER); myNametext.setBounds(38, 27, 80, 23); return container; } /** * Create contents of the button bar. * @param parent */ @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); m_bindingContext = initDataBindings(); } /** * Return the initial size of the dialog. */ @Override protected Point getInitialSize() { return new Point(362, 298); } public static void main(String[] args) { Display display = Display.getDefault(); Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() { public void run() { try { TestPojoBinding setting = new TestPojoBinding(null); setting.open(); } catch (Exception e) { e.printStackTrace(); } } }); } protected DataBindingContext initDataBindings() { DataBindingContext bindingContext = new DataBindingContext(); IObservableValue observeTextMyNametextObserveWidget = WidgetProperties.text(SWT.Modify).observe(myNametext); IObservableValue nameEditorConfigObserveValue = PojoProperties.value("name").observe(editorConfig); bindingContext.bindValue(observeTextMyNametextObserveWidget, nameEditorConfigObserveValue, null, null); return bindingContext; }}
PropertyChangeSupport
如果想要实现上面例子中数据对象属性与Text组件的内容双向同步绑定。解决方案之一就是改造数据对象Person,通过PropertyChangeSupport实现属性监控。
package testwb;import org.eclipse.jface.dialogs.Dialog;import org.eclipse.jface.dialogs.IDialogConstants;import org.eclipse.swt.graphics.Point;import org.eclipse.swt.widgets.Composite;import org.eclipse.swt.widgets.Control;import org.eclipse.swt.widgets.Shell;import org.eclipse.swt.SWT;import org.eclipse.swt.widgets.Text;import java.beans.PropertyChangeListener;import java.beans.PropertyChangeSupport;import org.eclipse.core.databinding.DataBindingContext;import org.eclipse.core.databinding.observable.value.IObservableValue;import org.eclipse.jface.databinding.swt.WidgetProperties;import org.eclipse.swt.widgets.Display;import org.eclipse.core.databinding.observable.Realm;import org.eclipse.jface.databinding.swt.DisplayRealm;import org.eclipse.swt.widgets.Button;import org.eclipse.swt.events.SelectionAdapter;import org.eclipse.swt.events.SelectionEvent;import org.eclipse.core.databinding.beans.BeanProperties;public class TestPojoBinding2 extends Dialog { public class ModelObject { private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); public void addPropertyChangeListener(PropertyChangeListener listener) { changeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { changeSupport.removePropertyChangeListener(listener); } protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { changeSupport.firePropertyChange(propertyName, oldValue, newValue); } } /** * 数据对象定义,继承ModelObject类,获取属性改变时被监控能力 * @author guyadong * */ public class Person extends ModelObject { private String name; public Person(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { // 修改set方法,在修改属性的同时,调用firePropertyChange通知所有侦听器属性已经改变 firePropertyChange("name", this.name, this.name = name); System.out.printf("updated %s\n",this.name); } } private DataBindingContext m_bindingContext; /** * 成员变量:数据对象 */ protected Person editorConfig=new Person("hello!"); private Text myNametext; /** * Create the dialog. * @param parentShell */ public TestPojoBinding2(Shell parentShell) { super(parentShell); } /** * Create contents of the dialog. * @param parent */ @Override protected Control createDialogArea(Composite parent) { Composite container = (Composite) super.createDialogArea(parent); container.setLayout(null); Button btnNewButton = new Button(container, SWT.NONE); btnNewButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { editorConfig.setName("word"); } }); btnNewButton.setBounds(38, 154, 80, 27); btnNewButton.setText("测试"); myNametext = new Text(container, SWT.BORDER); myNametext.setBounds(38, 27, 80, 23); return container; } /** * Create contents of the button bar. * @param parent */ @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); m_bindingContext = initDataBindings(); } /** * Return the initial size of the dialog. */ @Override protected Point getInitialSize() { return new Point(362, 298); } public static void main(String[] args) { Display display = Display.getDefault(); Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() { public void run() { try { TestPojoBinding2 setting = new TestPojoBinding2(null); setting.open(); } catch (Exception e) { e.printStackTrace(); } } }); } protected DataBindingContext initDataBindings() { DataBindingContext bindingContext = new DataBindingContext(); // 为Text组件创建观察对象 IObservableValue observeTextMyNametextObserveWidget = WidgetProperties.text(SWT.Modify).observe(myNametext); // 为数据对象属性创建观察对象 IObservableValue nameEditorConfigObserveValue = BeanProperties.value("name").observe(editorConfig); // 数据绑定 bindingContext.bindValue(observeTextMyNametextObserveWidget, nameEditorConfigObserveValue, null, null); // return bindingContext; }}
再运行程序,点击”测试”按钮,Text的值随着数据对象的属性同步改变了。
PojoBindable
上面这个方案已经实现了数据对象和UI组件的双向同步更新,但缺点就是需要对POJO对象进行改造,当项目中有多个POJO对象需要实现与UI组件的双同步更新时,这个工作量也是挺大的。
有没有办法在不改变现有POJO对象的代码的情况下,实现双向同步的目标呢?
有,解决方案就是本文的标题jface databinding/PojoBindable。[注意:这还是个实验项目,使用需谨慎]
PojoBindable利用ASM代码动态修改的技术,通过在运行时为POJO对象添加PropertyChangeSupport 的方法并修改setter方法,提供了一个途径让开发者在不修改自己的POJO类代码的情况下让POJO对象拥有完整的数据绑定能力。
凡事都有代价,使用PojoBindable想不修改POJO对象代码就拥有PropertyChangeSupport能力的话,代价是什么呢?
要修改JVM的运行参数
Pojo Bindable是一个Java Agent,所以为了使用PojoBindable,必须在java程序启动时指定jvm参数,用-javaagent
参数指定使用PojoBindable
-javaagent:<your path>/org.eclipse.core.databinding.pojo.bindable_1.0.0.jar
需要-Dbindable.packages
指定对哪些pojo对象进行修改java代码
-Dbindable.packages=org.eclipse.core.examples.databinding.pojo.bindable.model
需要 ASM支持
必须将 ObjectWeb ASM加入classpath
关于Pojo Bindable配置的更详细说明参见其官网原文:
https://wiki.eclipse.org/JFace_Data_Binding/PojoBindable#With_Pojo_Bindable
参考资料
《JFace Data Binding/PojoBindable》
《AJFace Data Binding - Tutorial》
- jface databinding/PojoBindable实现对POJO对象的支持
- jface databinding:部分实现POJO对象的监测
- jface databinding:重写doSetValue方法ComputedValue实现双向多对一的数据绑定
- jface databinding:List,Set,Map对象的Observable代理封装
- Struts学习(五):对POJO对象访问的支持
- 仅对具有 DataBinding 事件的对象提供数据绑定表达式支持。System.Web.UI.WebControls.HyperLinkField 没有 DataBinding 事件。
- jface databinding:使用CheckboxTableViewer实现表中(Set)对象与CheckTable中选中条目数据绑定
- Spring MVC POJO对象的支持
- jface databinding: Radio Button group及ISideEffect绑定数据对象的例子
- jface databinding:更简单的ISideEffect实现多目标单边数据绑定塈其原理分析
- jface databinding:label provider 实现多列表格(Table)数据绑定的两个途径
- jface databinding: 创建readonly(只读)可观察对象(observable)
- jface databinding:可多选的widget List组件selection项目与java.util.List对象的双向数据绑定
- jface databinding:延迟计算--ComputedValue和WritableList使用的例子
- Swt/Jface listviewer的实现
- Swt/Jface listviewer的实现
- jface的dialog实现非模态
- Swt/Jface listviewer的实现
- 上传文件的input框的change时间只能触发一次的原因
- shell脚本
- cocos2dx 3.12 各平台资源加密解密
- 用远程桌面登陆服务器 自动输入字母c
- 解决SSO客户端验证错误String index out of range
- jface databinding/PojoBindable实现对POJO对象的支持
- 选择器的优先级
- 14.3 Swift内存管理模型
- Ubuntu系统修改时区
- Linux 下JDK的安装和环境变量配置
- [AHK]将对话框路径置成刚查看过的文件夹路径(仿Listary功能)
- Hive 字段和表注释乱码
- mybatis一级缓存和二级缓存
- android系统开机画面log和动画的自定义