Java 如何覆盖Tapestry';s双向布尔强制与三向一?

Java 如何覆盖Tapestry';s双向布尔强制与三向一?,java,null,boolean,tapestry,coercion,Java,Null,Boolean,Tapestry,Coercion,考虑一下这个例子 您有一个不能以任何方式更改或扩展的类 public class Foo { ... private Boolean bar; ... } 您需要通过BeanEditor编辑该类的字段,但该类背后的逻辑允许并使用Boolean可以有三种状态:null、true和false 然而,Tapestry将为您提供一个只有两个选项的复选框,true或false 因此,在线人士建议您将Booleantype属性转换为BooleanExtendedEnumtype属性

考虑一下这个例子

您有一个不能以任何方式更改或扩展的类

public class Foo {
    ...
    private Boolean bar;
    ...
}
您需要通过
BeanEditor
编辑该类的字段,但该类背后的逻辑允许并使用
Boolean
可以有三种状态:nulltruefalse

然而,Tapestry将为您提供一个只有两个选项的复选框,truefalse

因此,在线人士建议您将
Boolean
type属性转换为
BooleanExtendedEnum
type属性,该属性可以表示三向逻辑

public enum BooleanExtendedEnum {
    UNDEFINED(null),
    TRUE(Boolean.TRUE),
    FALSE(Boolean.FALSE);

    private Boolean booleanValue;

    private static Map<Boolean, BooleanExtendedEnum> booleanToExtendedMap = new HashMap<Boolean, BooleanExtendedEnum>();


    static {
        for (BooleanExtendedEnum be : BooleanExtendedEnum.values()) {
            booleanToExtendedMap.put(be.booleanValue, be);
        }
    }

    private BooleanExtendedEnum(Boolean booleanValue) {
        this.booleanValue = booleanValue;
    }

    public Boolean getBooleanValue() {
        return booleanValue;
    }

    public static BooleanExtendedEnum getBooleanExtendedValue(Boolean booleanInput) {
        return booleanToExtendedMap.get(booleanInput);
    }

}
让我们假设您在
tml
中的
BeanEditor
中做了这样简单的事情:

<p:bar>
    <div class="t-beaneditor-row">
        <label>Bar Value</label>
        <t:select t:id="fooBar" t:value="foo.bar" t:model="booleanExtendedSelectModel" t:blankOption="NEVER"/>
    </div>
</p:bar>
Tapestry将创建一个包含三个选项的下拉列表

  • 未定义
  • True
  • False
但是,它将强制显示这些值的实际布尔值将是

  • 未定义
    ->正确
  • True
    ->True
  • False
    ->False

如何实现所需的效果(
未定义
->),而不更改类或将其包装到另一个类中,该类的
布尔
类型字段替换为
布尔扩展枚举
类型字段或使用任何其他“hacky”类型字段解决方案?

您可以向页面添加属性并使用自定义块

public enum Ternary {
    TRUE(Boolean.TRUE), FALSE(Boolean.FALSE), UNDEFINED(null);

    public static Ternary valueOf(Boolean value) { ... }
    public Boolean asBoolean() { ... }
}

public class MyPage {
    @Property
    private Foo foo;

    public Ternary getTernaryBar() {
       return Ternary.valueOf(foo.getBar());
    }

    public void setTernaryBar(Ternary tBar) {
       foo.setBar(tBar.asBoolean());
    }
}

<t:beaneditor t:id="foo" exclude="bar" add="ternaryBar">
    <p:ternaryBar>
       <t:label for="ternaryBar"/>
       <t:select t:id="ternaryBar" />
    </p:ternaryBar>
</t:beaneditor>
公共枚举{
TRUE(Boolean.TRUE)、FALSE(Boolean.FALSE)、未定义(null);
公共静态三元值(布尔值){…}
公共布尔值asBoolean(){…}
}
公共类MyPage{
@财产
私人富福;
公共三元getTernaryBar(){
返回三元.valueOf(foo.getBar());
}
公共无效设置栏(待定){
foo.setBar(tBar.asBoolean());
}
}
BeaneEditor和支持bean之间的“粘合剂”是。BeanModel由BeanModelSource创建,BeanModelSource反过来使用

使用
三元
而不是
布尔
来修饰PropertyConduitSource非常简单

乙二醇


我理解这个解决方案,但考虑到我在相当多的页面上有相当多的Foo类,这不是我正在寻找的解决方案。尽管如此,thx的努力:)这看起来很有趣,你可能有一个链接到一些例子?我相信我理解你在这里说的话,但因为我以前从未做过,我想确定:)我也从未做过。我已经为您提供了装饰方法的领先优势,但您需要实现TernaryBeanModelSource。添加了更改。现在简单多了啊,sry,没有看到你添加了更改,tyvm:)我也朝着类似的方向走,但是是的,这简单多了:)看来我还有很多关于Tapestry的知识要学。和往常一样,我非常感谢:DIt是一个自定义注释,您可以创建并命名您喜欢的方式
public SelectModel getBooleanExtendedSelectModel() {
    return new EnumSelectModel(BooleanExtendedEnum.class, messages);
}
public enum Ternary {
    TRUE(Boolean.TRUE), FALSE(Boolean.FALSE), UNDEFINED(null);

    public static Ternary valueOf(Boolean value) { ... }
    public Boolean asBoolean() { ... }
}

public class MyPage {
    @Property
    private Foo foo;

    public Ternary getTernaryBar() {
       return Ternary.valueOf(foo.getBar());
    }

    public void setTernaryBar(Ternary tBar) {
       foo.setBar(tBar.asBoolean());
    }
}

<t:beaneditor t:id="foo" exclude="bar" add="ternaryBar">
    <p:ternaryBar>
       <t:label for="ternaryBar"/>
       <t:select t:id="ternaryBar" />
    </p:ternaryBar>
</t:beaneditor>
public class MyAppModule {
    public PropertyConduitSource decoratePropertyConduitSource(final PropertyConduitSource old) {
       return new PropertyConduitSource() {
          public PropertyConduit create(Class rootType, String expression) { 
             PropertyConduit conduit = old.create(rootType, expression);

             // you cound also check for conduit.getAnnotation(AllowNull.class) 
             // and then annotate your bean properties for a more granular approach
             if (Boolean.class.equals(conduit.getPropertyType()) {
                return new TernaryPropertyConduit(conduit);
             }
             return conduit;
          }
       }
    }
}

public class TernaryPropertyConduit implements PropertyConduit {
   private PropertyConduit delegate;

   public getPropertyType() { return Ternary.class };

   public set(Object instance, Object value) {
      delegate.set(instance, ((Ternary) value).asBoolean());
   }

   public get(Object) {
      Boolean bValue = (Boolean) delegate.get(instance);
      return Ternary.valueOf(instance);
   }
}