jface databinding/PojoBindable实现对POJO对象的支持
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53811946
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 %sn",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 %sn",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》
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法