GWT Nested Editors - неправильно очищается или выдает ошибку, обнаруженную в цикле
Я создаю конструктор правил, похожий на этот:
Может быть два типа объектов правил:
- JoinMetadataCondition: содержит тип объединения ("и" или "или") и список других условий метаданных для присоединения
- LeafMetadataCondition: содержит определение правила (переменная, оператор, значение)
Оба эти условия реализуют интерфейс MetadataCondition.
Подход 1
Я использовал три разных редактора, чтобы попытаться редактировать правила, но я получаю ошибку, обнаруженную циклом, которая имеет смысл, так как правила рекурсивные. Ниже приведены три редактора.
MetadataConditionEditor
Это использует AbstractSubTypeEditor, описанный здесь и здесь
Это точка входа в редакторы правил. Ему будет дано условие метаданных верхнего уровня, и оттуда он присоединится к соответствующему редактору.
public class MetadataConditionEditor extends Composite implements Editor<MetadataCondition> {
interface Binder extends UiBinder<Widget, MetadataConditionEditor> {}
@Ignore
final JoinMetadataConditionEditor joinMetadataEditor = LibsFactory.injector().getJoinMetadataConditionEditor();
@Path("")
final AbstractSubTypeEditor<MetadataCondition, JoinMetadataCondition, JoinMetadataConditionEditor> joinMetadataEditorWrapper =
new AbstractSubTypeEditor<MetadataCondition, JoinMetadataCondition, JoinMetadataConditionEditor>( joinMetadataEditor ) {
@Override
public void setValue( final MetadataCondition value )
{
setValue( value, isJoinMetadataCondition( value ) );
if( isJoinMetadataCondition( value ) ) {
container.clear();
container.add( joinMetadataEditor );
}
}
};
@Ignore
final LeafMetadataConditionEditor leafMetadataEditor = LibsFactory.injector().getLeafMetadataConditionEditor();
@Path("")
final AbstractSubTypeEditor<MetadataCondition, LeafMetadataCondition, LeafMetadataConditionEditor> leafMetadataEditorWrapper =
new AbstractSubTypeEditor<MetadataCondition, LeafMetadataCondition, LeafMetadataConditionEditor>( leafMetadataEditor ) {
@Override
public void setValue( final MetadataCondition value )
{
setValue( value, !isJoinMetadataCondition( value ) );
if( !isJoinMetadataCondition( value ) ) {
container.clear();
container.add( leafMetadataEditor );
}
}
};
@UiField @Ignore SimplePanel container;
public MetadataConditionEditor() {
initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );
}
private Boolean isJoinMetadataCondition( MetadataCondition value ) {
return value instanceof JoinMetadataCondition;
}}
JoinMetadataConditionEditor
Используется для редактирования объектов JoinMetadataCondition
открытый класс JoinMetadataConditionEditor расширяет составные реализации редактора {интерфейс Binder расширяет UiBinder {}
@UiField @Ignore FlowPanel container;
@UiField
@Path( "type" )
ManualSelectEditor type;
@Path( "conditions" )
ListEditor<MetadataCondition, MetadataConditionEditor> conditions;
public JoinMetadataConditionEditor() {
initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );
conditions = ListEditor.of( new MetadataEditorSource() );
type.setSelectOptions( EditorConstants.metadataJoins );
}
private class MetadataEditorSource extends EditorSource<MetadataConditionEditor>
{
@Override
public MetadataConditionEditor create( int index )
{
final MetadataConditionEditor subEditor = new MetadataConditionEditor();
container.insert( subEditor, index );
return subEditor;
}
public void dispose( MetadataConditionEditor subEditor ) {
container.remove( subEditor );
}
}}
LeafMetadataConditionEditor
И, наконец, редактор, используемый для LeafMetadataCondition
public class LeafMetadataConditionEditor extends Composite implements Editor<LeafMetadataCondition> {
interface Binder extends UiBinder<Widget, LeafMetadataConditionEditor> {}
@UiField TextBoxEditor name;
@UiField TextBoxEditor value;
@UiField ManualSelectEditor operator;
public LeafMetadataConditionEditor() {
initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
operator.setSelectOptions( EditorConstants.metadataOperators );
}
}
Вопрос
Вопрос заключается в следующем: как избежать ошибки, обнаруженной в цикле, или создать эту рекурсивную работу таким образом, чтобы она работала?
Примечание: я открыт для новых способов сделать это. Я пробовал несколько других маршрутов, таких как инициализация драйверов для каждого подредактора и создание их всех CompositeEditors. Это скомпилировано и загружено, но когда пришло время сбрасывать драйверы, значения подредактора не создавались должным образом, даже если казалось, что методы flush() вызывались, но значения тогда не использовались родительскими редакторами.
Подход 2
Второй подход заключается в использовании CompositeEditor и создании под-редакторами своих собственных драйверов, которые затем сбрасываются для создания конечного результата.
MetadataConditionEditor
public class MetadataConditionEditor extends Composite implements
CompositeEditor<MetadataCondition, MetadataCondition, SimpleDriverEditor<MetadataCondition>>,
LeafValueEditor<MetadataCondition>
{
interface Binder extends UiBinder<Widget, MetadataConditionEditor> {}
// private SimpleBeanEditorDriver<MetadataCondition, ? extends Editor<MetadataCondition>> subDriver;
private EditorChain<MetadataCondition, SimpleDriverEditor<MetadataCondition>> chain;
private SimpleDriverEditor<MetadataCondition> subEditor;
private EditorDelegate<MetadataCondition> delegate;
private MetadataCondition value;
@UiField @Ignore SimplePanel container;
public MetadataConditionEditor() {
initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );
}
@Override
public void flush()
{
if( Utils.isNull( subEditor ) )
return;
GWT.log( "----- flush-pre - " + System.identityHashCode(this) + " - " + value );// TODO
value = subEditor.flush();
GWT.log( "----- flush-post-1 - " + System.identityHashCode(this) + " - " + value.toJson() );// TODO
}
@Override
public void onPropertyChange(String... paths) {}
@Override
@SuppressWarnings("unchecked")
public void setValue( MetadataCondition value )
{
this.value = value;
// subDriver = null;
if( Utils.isNull( value ) )
return;
GWT.log( "----- setValue - " + value );// TODO
if( value instanceof JoinMetadataCondition ) {
SimpleDriverEditor<JoinMetadataCondition> newSubEditor = LibsFactory.injector().getJoinMetadataConditionEditor();
SimpleDriverEditor<? extends MetadataCondition> newSubEditor1 = newSubEditor;
subEditor = (SimpleDriverEditor<MetadataCondition>) newSubEditor1;
newSubEditor.edit( (JoinMetadataCondition) value );
}
container.clear();
container.add( subEditor );
}
@Override
public void setDelegate( EditorDelegate<MetadataCondition> delegate ) {
GWT.log( "----- setDelegate - " + delegate );// TODO
this.delegate = delegate;
}
@Override
public MetadataCondition getValue() {
GWT.log( "----- getValue - " + System.identityHashCode(this) + " - " + value );// TODO
return value;
}
@Override
public SimpleDriverEditor<MetadataCondition> createEditorForTraversal() {
GWT.log( "----- createEditorForTraversal - " + subEditor );// TODO
return subEditor;
}
@Override
public String getPathElement( SimpleDriverEditor<MetadataCondition> subEditor ) {
GWT.log( "----- getPathElement - " + delegate.getPath() );// TODO
return delegate.getPath();
}
@Override
public void setEditorChain( EditorChain<MetadataCondition, SimpleDriverEditor<MetadataCondition>> chain ) {
GWT.log( "----- setEditorChain - " + chain );// TODO
this.chain = chain;
}
}
JoinMetadataConditionEditor
public class JoinMetadataConditionEditor extends Composite implements SimpleDriverEditor<JoinMetadataCondition>
{
interface Binder extends UiBinder<Widget, JoinMetadataConditionEditor> {}
interface Driver extends SimpleBeanEditorDriver<JoinMetadataCondition, JoinMetadataConditionEditor> {}
private Driver driver = GWT.create(Driver.class);
@Inject
ModelFactory factory;
@UiField @Ignore HTML label;
@UiField @Ignore FlowPanel container;
@UiField @Ignore Button deleteMetadata;
@UiField
@Path( "type" )
ManualSelectEditor type;
@Path( "conditions" )
ListEditor<MetadataCondition, MetadataConditionEditor> conditions = ListEditor.of( new MetadataEditorSource() );
public JoinMetadataConditionEditor() {
initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );
type.setSelectOptions( EditorConstants.metadataJoins );
}
public SimpleBeanEditorDriver<JoinMetadataCondition, JoinMetadataConditionEditor> createDriver() {
driver.initialize( this );
return driver;
}
@Override
public JoinMetadataCondition flush()
{
GWT.log( "---------- flush-pre - " + System.identityHashCode(this) + " - " + type.getValue() );// TODO
GWT.log( "---------- flush-pre - " + System.identityHashCode(this) + " - " + conditions.getList() );// TODO
JoinMetadataCondition value = driver.flush();
GWT.log( "---------- flush-post - " + System.identityHashCode(this) + " - " + value.toJson() );// TODO
return value;
}
@Override
public void edit( JoinMetadataCondition object ) {
createDriver();
driver.edit( object );
label.setText( getLabel( object ) );
}
private String getLabel( JoinMetadataCondition value ) {
if( StringUtils.equals( value.getType(), JoinMetadataTypes.AND.value() ) )
return LibsFactory.lang().allConditionsAreTrue();
return LibsFactory.lang().anyConditionsAreTrue();
}
@Override
public HandlerRegistration addDeleteHandler( MetadataDeletedHandler handler ) {
return addHandler( handler, MetadataDeletedEvent.TYPE );
}
@UiHandler("deleteMetadata")
protected void onDeleteMetadata( ClickEvent event ) {
fireEvent( new MetadataDeletedEvent( (Event) event.getNativeEvent() ) );
}
@UiHandler("addAllMetadata")
protected void onAddAllMetadata(ClickEvent event) {
add( factory.newJoinMetadataCondition( JoinMetadataTypes.AND ) );
}
@UiHandler("addOrMetadata")
protected void onAddOrMetadata(ClickEvent event) {
add( factory.newJoinMetadataCondition( JoinMetadataTypes.OR ) );
}
@UiHandler("addLeafMetadata")
protected void onAddLeafMetadata(ClickEvent event) {
add( factory.newLeafMetadataCondition() );
}
private void add( MetadataCondition metadata ) {
try {
GWT.log("--------------------------------- add() - pre");// TODO
conditions.getList().add( metadata );
clearErrors();
} catch (Exception e) {
GWT.log("--------------------------------- add() - " + e.getMessage()); // TODO
}
}
public void clearErrors() {
type.getErrorHandler().clearErrors();
}
private class MetadataEditorSource extends EditorSource<MetadataConditionEditor>
{
@Override
public MetadataConditionEditor create( int index )
{
final MetadataConditionEditor subEditor = new MetadataConditionEditor();
container.insert( subEditor, index );
return subEditor;
}
public void dispose( MetadataConditionEditor subEditor ) {
container.remove( subEditor );
}
}
}
вопрос
Этот второй подход, кажется, почти работает. Проблема в том, что когда я сбрасываю драйвер, вспомогательные драйверы также сбрасываются, но по какой-то причине родительские редакторы фактически не включают значения подредакторов.
Приведенные выше операторы журнала генерируют следующий вывод, когда у меня есть одно вложенное условие соединения:
----- flush-pre - 111 - JoinMetadataCondition@2d1
---------- flush-pre - 761 - null
---------- flush-pre - 761 - [JoinMetadataCondition@379]
----- flush-pre - 886 - JoinMetadataCondition@379
---------- flush-pre - 929 - and
---------- flush-pre - 929 - []
---------- flush-post - 929 - {"type":"and", "conditions":[]}
----- flush-post-1 - 886 - {"type":"and", "conditions":[]}
----- getValue - 886 - JoinMetadataCondition@379
---------- flush-post - 761 - {"type":"and", "conditions":[]}
----- flush-post-1 - 111 - {"type":"and", "conditions":[]}
----- getValue - 111 - JoinMetadataCondition@2d1
{"type":"and", "conditions":[]}
Как вы можете видеть, главный редактор (111) на самом деле не включает содержимое своих подредакторов. Есть идеи, почему это может быть?
1 ответ
К сожалению, я не мог заставить это работать, используя структурированный подход редактора.
Окончательное решение состояло в том, чтобы создать LeafValueEditor и построить форму "вручную" на основе данных, предоставленных через setValue(). Я также реализовал HasEditorErrors для правильной обработки ошибок.