JavaBeans的替代品?

时间:2009-01-13 23:05:06

标签: java properties javabeans

我讨厌JavaBeans模式的激情像一千个太阳的火焰一样燃烧。为什么呢?

  • 冗长即可。这是2009年。我不应该为房产写7 LOC。如果他们有事件听众,那就抓住你的帽子。
  • 没有类型安全的参考。没有类型安全的方法来引用属性。 Java的全部意义在于它是类型安全的,并且它最流行的模式并不是所有类型都安全的。

我想要的是:

class Customer {
    public Property<String> name = new Property();
}

我主要是网络开发人员,因此需要JPA和Wicket支持。

帮我离开javabean火车!

11 个答案:

答案 0 :(得分:10)

我认为你与你在那里的宣言非常接近(见下面的草图)。但是,通过使用非bean方法,您可能会失去大多数假定JavaBeans协议生效的工具所提供的支持。请善待。下面的代码不在我的脑海......

public class Property<T> {
    public final String name;
    T value;
    private final PropertyChangeSupport support;

    public static <T> Property<T> newInstance(String name, T value, 
                                              PropertyChangeSupport support) {
        return new Property<T>(name, value, support);
    }

    public static <T> Property<T> newInstance(String name, T value) {
        return newInstance(name, value, null);
    }

    public Property(String name, T value, PropertyChangeSupport support) {
        this.name = name;
        this.value = value;
        this.support = support;
    }

    public T getValue() { return value; }

    public void setValue(T value) {
        T old = this.value;
        this.value = value;
        if(support != null)
            support.firePropertyChange(name, old, this.value);
    }

    public String toString() { return value.toString(); }
}

然后继续使用它:

public class Customer {
    private final PropertyChangeSupport support = new PropertyChangeSupport();

    public final Property<String> name = Property.newInstance("name", "", support);
    public final Property<Integer> age = Property.newInstance("age", 0, support);

    ... declare add/remove listenener ...
}


Customer c = new Customer();
c.name.setValue("Hyrum");
c.age.setValue(49);
System.out.println("%s : %s", c.name, c.age);

因此,现在声明属性是一行代码,并包含属性更改支持。我调用了方法setValue()和getValue(),所以它仍然看起来像一个bean来代码像Rhino和东西,但为了简洁,你可以添加get()和set()。其余部分留给读者练习:

  • 正确处理序列化
  • 处理空值检查
  • 如果你关心自动装箱开销,可能会为原子类型添加一个专门化。
  • ?我相信还有更多的问题

另请注意,您可以子类化(通常作为匿名类)并覆盖setValue()以提供其他参数检查。

我认为你不能真正摆脱“字符串引用”,因为这几乎就是反思所在。

可悲的是,在这个时代,这仍然有点像汇编编程......如果你有选择的话,Groovy,C#等等可能仍然是更好的选择。

答案 1 :(得分:4)

查看我的Bean注释

http://code.google.com/p/javadude/wiki/Annotations

基本上你做的事情如下:

@Bean(
  properties={
    @Property(name="name"),
    @Property(name="phone", bound=true),
    @Property(name="friend", type=Person.class, kind=PropertyKind.LIST)
  }
)
public class Person extends PersonGen {}

而不是自己定义所有额外的get / set等方法。

还有其他属性来定义equals / hashCode,observers,delegates,mixins等。

它是一组注释和注释处理器,可以在eclipse或命令行构建中运行(例如在ant中)。处理器生成一个超类来包含所有生成的代码(注释处理器不能更改包含注释的类,顺便说一句)

答案 2 :(得分:3)

您可能需要查看Groovy - 一种具有“真实”属性的动态类型,基于JVM(和完全兼容Java)的语言。

答案 3 :(得分:2)

使用Spring Framework。它的目的是通过抽象你抱怨的许多基础来简化Java开发。

您可以将它与Hibernate一起使用,这样可以简化与数据源的交互。

有用的网站:

www.springsource.org/download

www.hibernate.org /

答案 4 :(得分:1)

对于网络,我建议使用JSON(JavaScript Object Notation),

  

轻量级数据交换格式

。这是对JSON?Bean translator的引用。

答案 5 :(得分:1)

当我第一次使用C#时,我喜欢这些属性,但是现在,在使用VS 2008一段时间之后,我不得不说我更喜欢set- / get-methods。

重点是我个人的工作方式。当我有一个新类并且我想知道我能用它做什么时,我只需输入classname.set,Eclipse就会向我显示我可以更改的“属性”。同样可以获得。也许它只是可怜的VS方式,但在那里我必须通过这个itelisense的长列表(其中所有内容混合,而不是首先显示属性)只是为了找出我编译后我想要设置的属性是readonly。 ..doh!

是的,在Java中你需要很多行,但我只是编写我的属性并告诉IDE“请为我创建getter和setter”。但是这些方法往往会占用大量空间,这就是为什么我想在Java中使用区域,以便我可以在IDE中折叠。

答案 6 :(得分:0)

您还可以构建一个代码生成器,从您编写的DSL创建.java类。您可以使用某种标记来描述类的名称,所需的属性及其类型。然后,使用生成javabeans的程序处理该文件。或者你可以使用注释,并使用类似ASM的东西对类文件进行后处理以注入访问器和放大器。存取器。我也相信Spring提供了一些这样的功能,但我没有使用它们。

答案 7 :(得分:0)

从JBoss尝试SEAM框架,您应该喜欢它。

答案 8 :(得分:0)

我试过这个:

interface IListenable {
    void addPropertyChangeListener( PropertyChangeListener listener );
    void removePropertyChangeListener( PropertyChangeListener listener );
}

abstract class MyBean extends IListenable {
    public abstract void setName(String name);
    public abstract String getName();

    // more things
}

public class JavaBeanFactory {

   public <T> Class<T> generate(Class<T> clazz) {
      // I used here CGLIB to generate dynamically a class that implements the methods:
      // getters
      // setters
      // addPropertyChangeListener
      // removePropertyChangeListener
   }
}

我用它作为这个(这只是一个例子):

public class Foo {
    @Inject
    public Provider<MyBean> myBeanProvider;

    public MyBean createHook(MyBean a) {
        final MyBean b  = myBeanProvider.get();
        a.addPropertyChangeListener(new PropertyChangeListener() {
             public void propertyChange(PropertyChangeEvent evt) {
                 b.setName((String) evt.getNewValue());
             }
        });
        return b;
    }
}

答案 9 :(得分:0)

我在我的模型实体(使用JPA注释)上大量使用JavaBean属性,以便能够将它们数据绑定到UI(使用JFace)。

遗憾的是,我没有针对第二个问题的解决方案(可能除了定义包含属性名称的常量之外)。

我生成监听器样板的方法是让我的模型实体从AbstractJavaBean超类扩展,该超类使用反射来处理它。然后我可以使用创建getter / setter的默认方式,除了setter需要重写如下:

public void setRemarks(String remarks) {
    set("remarks", remarks);
}

AbstractJavaBean.set然后使用反射(通过Apache commons beanutils)通过其getter读取属性“remarks”的旧值,将新值设置为名为“remarks”的字段,并使用旧的方法触发属性更改事件和新的价值观。实际上,这个想法可以扩展为使得依赖的“派生”属性能够在属性“birthDate”被更改时基于诸如“age”之类的变化的属性之一自动触发属性更改。所有这些逻辑都可以在AbstractJavaBean中的一个位置编码,并由任何模型对象使用。

答案 10 :(得分:0)

我正在寻找同样的事情,我真的很惊讶我找不到合适的图书馆。由于我经常感到痛苦,所以我在两年前开始了一个解决这些问题的小项目:属性

可从以下位置获取: https://github.com/aditosoftware/propertly。 我们现在正在使用它。

它提供静态类型,包括泛型,不同级别的侦听器,树中导航,动态模型等。 主要优点是模型的描述是静态完成的,因此信息始终可用,并且设计时考虑了可扩展性。因此,您可以使用自己的注释进行验证,或者定义数据的读取和存储位置。

使用示例:

一个简单的IPropertyPitProvider。属性是名字,姓氏和年龄。

// Generics describe parent, self and children
public class StudentPropertyPitProvider 
    extends AbstractPPP<IPropertyPitProvider, StudentPropertyPitProvider, Object>
{
  // IPropertyDescription gives static access to an IProperty's meta data like name and type.
  public static final IPropertyDescription<StudentPropertyPitProvider, String> FIRST_NAME =
      PD.create(StudentPropertyPitProvider.class);

  public static final IPropertyDescription<StudentPropertyPitProvider, String> LAST_NAME =
      PD.create(StudentPropertyPitProvider.class);

  public static final IPropertyDescription<StudentPropertyPitProvider, Integer> AGE =
      PD.create(StudentPropertyPitProvider.class);


  // Getters and setters can of course still be used for easier access. 
  public String getFirstName()
  {
    // getValue and setValue is available at AbstractPPP. That class is used for easier access. 
    // Propertly can be used without inheriting from that class, too.
    return getValue(FIRST_NAME);
  }

  public void setFirstName(String pFirstName)
  {
    setValue(FIRST_NAME, pFirstName);
  }

  public String getLastName()
  {
    return getValue(LAST_NAME);
  }

  public void setLastName(String pLastName)
  {
    setValue(LAST_NAME, pLastName);
  }

  public Integer getAge()
  {
    return getValue(AGE);
  }

  public void setAge(Integer pAge)
  {
    setValue(AGE, pAge);
  }

}

使用已定义的提供者:

public class Sample
{

  public static void main(String[] args)
  {
    // Hierarchy is necessary to initialize the IPropertyPitProviders and for advanced features.
    Hierarchy<StudentPropertyPitProvider> hierarchy =
        new Hierarchy<>("student1", new StudentPropertyPitProvider());
    // The created student can be accessed from the hierarchy.
    StudentPropertyPitProvider student = hierarchy.getValue();
    // Listeners can be added.
    student.addPropertyEventListener(new PropertyPitEventAdapter()
    {
      @Override
      public void propertyChanged(IProperty pProperty, Object pOldValue, Object pNewValue)
      {
        System.out.println(pProperty.getName() + "=" + pNewValue);
      }
    });

    // The following calls will cause
    //  FIRST_NAME=Nils
    //  LAST_NAME=Holgersson
    //  AGE=32
    // to be printed on console through the listener.
    student.setFirstName("Nils");
    student.setLastName("Holgersson");
    student.setAge(32);
  }

}