前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jface databinding/PojoBindable实现对POJO对象的支持

jface databinding/PojoBindable实现对POJO对象的支持

作者头像
10km
发布2019-05-25 22:28:49
5040
发布2019-05-25 22:28:49
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433701

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控件的值并没有同步变化。

代码语言:javascript
复制
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实现属性监控。

代码语言:javascript
复制
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

代码语言:javascript
复制
-javaagent:<your path>/org.eclipse.core.databinding.pojo.bindable_1.0.0.jar

需要-Dbindable.packages指定对哪些pojo对象进行修改java代码

代码语言:javascript
复制
-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》

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年12月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • POJO对象无法被监控
  • PropertyChangeSupport
  • PojoBindable
    • 要修改JVM的运行参数
      • 需要 ASM支持
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档