2

考虑这种情况。

您有一个无法以任何方式更改或扩展的类。

public class Foo {
    ...
    private Boolean bar;
    ...
}

您需要通过 编辑该类的字段BeanEditor,但该类背后的逻辑允许并使用Boolean可以具有 3 种状态的事实:nulltruefalse

然而,Tapestry 会给你一个只有 2 个选项的复选框,truefalse

所以,网上有人建议你把你的Booleantype 属性转换成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);
    }

}

由于您无法更改Foo班级,因此您需要为Boolean <=> BooleanExtendedEnum.

Coercion<Boolean, BooleanExtendedEnum> threeWayBooleanToExtended = new Coercion<Boolean, BooleanExtendedEnum>() {
    @Override
    public BooleanExtendedEnum coerce(Boolean input) {
        if (input == null) {
            return BooleanExtendedEnum.UNDEFINED;
        } else {
            return BooleanExtendedEnum.getBooleanExtendedEnumValue(input);
        }
    }
};

Coercion<BooleanExtendedEnum, Boolean> threeWayExtendedToBoolean = new Coercion<BooleanExtendedEnum, Boolean>() {
    @Override
    public Boolean coerce(BooleanExtendedEnum input) {
        if (input == null) {
            return null;
        } else {
            return input.getBooleanValue();
        }
    }
};

configuration.add(new CoercionTuple<Boolean, BooleanExtendedEnum>(Boolean.class, BooleanExtendedEnum.class, threeWayBooleanToExtended));
configuration.add(new CoercionTuple<BooleanExtendedEnum, Boolean>(BooleanExtendedEnum.class, Boolean.class, threeWayExtendedToBoolean));

假设你在你的 in 中做了这么简单的BeanEditor事情tml

<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>

...并提供SelectModel这样的:

public SelectModel getBooleanExtendedSelectModel() {
    return new EnumSelectModel(BooleanExtendedEnum.class, messages);
}

Tapestry 将创建一个包含三个选项的下拉列表

  • Undefined
  • True
  • False

但是,它将强制显示的值的真正布尔值将是

  • Undefined->真的
  • True->真的
  • False->假的

如何在不更改类或将其包装在另一个将类型字段替换为类型字段或使用任何其他“hacky”解决方案的类中达到预期效果( Undefined-> null )?BooleanBooleanExtendedEnum

4

2 回答 2

1

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

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>
于 2014-02-19T14:52:10.947 回答
1

BeanEditor 和支持 bean 之间的“粘合剂”是BeanModel。BeanModels 由 BeanModelSource 创建,后者又使用PropertyConduitSource

装饰 PropertyConduitSource 以使用Ternary而不是Boolean.

例如

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);
   }
}
于 2014-02-20T08:39:41.413 回答