在前一篇博文《jface databinding/PojoBindable实现对POJO对象的支持 》中,已经知道直接对POJO对象进行修改,是不能被绑定的UI组件知道的,在上一篇文章中虽然说到PojoBindable这个项目可以解决这个问题,但这个项目并不成熟,所以我没有采用这个方案,而且如果要改造所有的POJO类支持PropertyChangeSupport又实在太麻烦了。 仔细想想我的需求,退而求其次,不一定要直接修改POJO对象,就能实现数据同步可以不? 冷静回头再看相关的资料并做了一些试验,发现原来IObservableValue对象本身就有setValue方法用于修改被监控的对象的值,而且会通知到观察对象。
DataBindingContext bindingContext = new DataBindingContext();
// Text对象的text属性的IObservableValue 对象
IObservableValue observeTextMyNametextObserveWidget = WidgetProperties.text(SWT.Modify).observe(myNametext);
// Person对象name属性的IObservableValue 对象(Person是个实现了属性get/set方法的POJO类)
namePersonObserveValue = http://blog.csdn.net/10km/article/details/PojoProperties.value("name").observe(person);
// 数据绑定
bindingContext.bindValue(observeTextMyNametextObserveWidget, namePersonObserveValue, null, null);
// 调用IObservableValue.setValue方法修改数据对象的值,Text的内容会同步更新
namePersonObserveValue.setValue("word");
// 直接调用Person.setName方法来修改数据对象,Text不同步更新。
person.setName("word")
这不就行了?将POJO对象封装起来提供IObservableValue,所有的Set方法IObservableValue.setValue方法来实现,后续修改POJO对象改为调用这个封装对象的Set方法,不就可以实现POJO对象的数据的监控了吗? 关键是在我这个项目里这样做的成本并不高,只是后续要改变一下对POJO对象的访问方式而已。于是根据这个思路,我写了一个稍通用化的POJO封装类来实现这个想法儿: 分两个类
ObservablePojoType 对POJO类进行可监控封装,为类的每个属性创建对应的{@link IBeanValueProperty} ObservablePojoObject 对POJO对象进行可监控封装,为对象的每个属性创建对应的{@link IObservableValue}, 提供 setValuegetValue方法实现对POJO对象进行访问 ObservablePojoType.java
package testwb;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.databinding.beans.IBeanValueProperty;
import org.eclipse.core.databinding.beans.PojoProperties;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import net.gdface.utils.Assert;
import net.gdface.utils.BeanPropertyUtils;
/**
* 对POJO类进行可监控封装,为POJO类的每个属性创建对应的{@link IBeanValueProperty}
* @see {@link PojoProperties#value(String)}
* @see {@link IBeanValueProperty#observe(Object)}
* @author guyadong
*
* @param <T> 封装的POJO类
*/
public class ObservablePojoType<T> {
private final Class<T> pojoType;
private Map<String,IBeanValueProperty> ivalueProperties=new HashMap<String, IBeanValueProperty>();
private final Map<String, PropertyDescriptor> propertyDescriptors;
public ObservablePojoType(Class<T> pojoType) {
if(null==pojoType)
throw new NullPointerException();
this.pojoType=pojoType;
// 返回所有可读写的属性
propertyDescriptors=BeanPropertyUtils.getProperties(pojoType, 3);
}
public ObservablePojoType(T pojo) {
this((Class<T>) pojo.getClass());
}
/**
* 返回POJO类的所有属性名
* @return
*/
public Set<String> getPropertyNames() {
return propertyDescriptors.keySet();
}
/**
* 返回source对象的指定属性(propertyName)的{@link IObservableValue}对象
* @param source 监控目标对象
* @param propertyName 属性名
* @return
*/
public IObservableValue<T> observe(T source,String propertyName) {
if(null==source)http://www.90168.org/
throw new NullPointerException();
if(null==propertyName||propertyName.empty())
throw new IllegalArgumentException();
if(!propertyDescriptors.containsKey(propertyName))
throw new IllegalArgumentException(String.format("invalid propertyName:%s",propertyName));
if(!ivalueProperties.containsKey(propertyName)){
ivalueProperties.put(propertyName, PojoProperties.value(propertyName));
}
return ivalueProperties.get(propertyName).observe(source);
}
/**
* 返回指定对象的监控对象{@link ObservablePojoObject}
* @param source
* @return
*/
public ObservablePojoObject<T> observe(T source){
return new ObservablePojoObject<T>(source,this);
}
public PropertyDescriptor[] getPropertyDescriptors() {
return propertyDescriptors.values().toArray(new PropertyDescriptor[0]);
}
}
ObservablePojoObject.java
package testwb;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper;
/**
* 对POJO对象进行可监控封装,为对象的每个属性创建对应的{@link IObservableValue}<br>
* {@link #setValue(String, Object)}和 {@link #getValue(String)}实现对POJO对象进行访问<br>
* 当调用 {@link #setValue(String, Object)}改变对象的属性值时,会自动通知监控对象<br>
*
* 这里将普通的Java bean(有get/set方法但没有通过PropertyChangeSupport实现属性监控)定义为POJO对象
* @author guyadong
*
* @param <T> 封装的POJO类
*/
public class ObservablePojoObject<T> {
private final T pojo;
private final ObservablePojoType<T> pojoType;
/**
* 每个属性对应的{@link IObservableValue}
*/
private final Map<String,IObservableValue> observableValues=new HashMap<String, IObservableValue>();
public ObservablePojoObject(T pojo,ObservablePojoType<T> pojoType) {
if(null==pojo)http://www.90168.org/
throw new NullPointerException();
this.pojo = pojo;
this.pojoType = null==pojoType?new ObservablePojoType<T>((Class<T>) pojo.getClass()):pojoType;
}
public ObservablePojoObject(T pojo) {
this(pojo,null);
}
/**
* 返回指定属性对应的{@link IObservableValue}对象
* @param propertyName
* @return
*/
public IObservableValue getObservableProperty(String propertyName){
if(!pojoType.getPropertyNames().contains(propertyName))
throw new IllegalArgumentException(String.format("invalid propertyName:%s",propertyName));
if(!observableValues.containsKey(propertyName)){
observableValues.put(propertyName, pojoType.observe(pojo, propertyName));
}
return observableValues.get(propertyName);
}
/**
* 设置指定属性的值
* @param propertyName
* @param value
*/
public void setValue(String propertyName,Object value){
getObservableProperty(propertyName).setValue(value);
}
/**
* 获取指定属性的值
* @param propertyName
* @return
*/
public Object getValue(String propertyName){
return getObservableProperty(propertyName).getValue();
}
public T getPojo() {
return pojo;
}
/**
* 用from对象更新当前监控对象的所有属性
* @param from
* @return
* @see #setValue(String, Object)
* @see {@link BeanPropertyHelper#readProperty(Object, PropertyDescriptor)}
*/
public ObservablePojoObject<T> updateFrom(T from){
if(null==from)
throw new NullPointerException();
for(PropertyDescriptor propertyDescriptor:pojoType.getPropertyDescriptors()){
setValue(propertyDescriptor.getName(), BeanPropertyHelper.readProperty(from, propertyDescriptor));
}
return this;
}
}
测试代码: TestPojoBinding4.java
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;
public class TestPojoBinding4 extends Dialog {
/**
* 数据对象定义
* @author guyadong
*
*/
public class Person {
private String name;
public Person(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 Person personBak=new Person("hello!");
protected Person person=new Person("hello!");
private Text myNametext;
private final ObservablePojoObject<Person> observablePersion=new ObservablePojoObject<Person>(person);;
/**
* Create the dialog.
* @param parentShell
*/
public TestPojoBinding4(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() {
@SuppressWarnings("unchecked")
@Override
public void widgetSelected(SelectionEvent e) {
// 修改 person的name属性
observablePersion.setValue("name", "word");
}
});
btnNewButton.setBounds(38, 154, 80, 27);
btnNewButton.setText("测试");
myNametext = new Text(container, SWT.BORDER);
myNametext.setBounds(38, 27, 80, 23);
Button btnNewButton_1 = new Button(container, SWT.NONE);
btnNewButton_1.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// 修改 person的name属性
observablePersion.updateFrom(personBak);
}
});
btnNewButton_1.setBounds(132, 154, 80, 27);
btnNewButton_1.setText("恢复");
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 {
TestPojoBinding4 setting = new TestPojoBinding4(null);
setting.open();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
protected DataBindingContext initDataBindings() {
DataBindingContext bindingContext = new DataBindingContext();
IObservableValue observeTextMyNametextObserveWidget = WidgetProperties.text(SWT.Modify).observe(myNametext);
// 数据绑定
bindingContext.bindValue(observeTextMyNametextObserveWidget, observablePersion.getObservableProperty("name"), null, null);
//
return bindingContext;
}
}