1

正如标题所示,我想创建一个基于 JSON Schema(我实时获取)的 Swing GUI,并使用它来填充 JSONObject(Google SimpleJSON)。我正在考虑为此使用 Metawidget 框架,但到目前为止还没有成功。我在网上找到了各种参考资料,但似乎没有一个适用于这种特殊情况。示例中总是缺少一些类或方法,而且 Metawidget 的文档也不是很好(至少我无法找到 4.2 版的一组示例)。我得到的 JSON Schema 描述了在服务器端使用 Jackson 的 JSONSchema 描述的 Java 类,但在本地不可用或可以事先知道,因此也应该处理。

有没有人对不同的方法有任何建议,或者我可以使用一些示例/参考?当然,使用 Metawidget 4.2 编译的具体代码也更受欢迎。

--- 编辑 --- (由于理查德肯纳德的回应)

使用提供的代码块,我设法生成了一个 GUI。但是,我需要修改“json”和“jsonSchema”字符串的值并插入其他值,并切换传递给 CompositeInspector 的检查器的顺序。这是代码和生成的 GUI:

final JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

String json = "{\"person\": { \"firstname\": \"Richard\", \"surname\": \"Kennard\", \"notes\": \"Software developer\" }}";
String jsonSchema = "{ \"name\": \"person\", \"type\": \"person\", properties: { \"firstname\": { \"required\": true }, \"surname\": { \"required\": true }, \"notes\": { \"large\": true }}}";

final SwingMetawidget metawidget = new SwingMetawidget();
metawidget.setInspector( new CompositeInspector( new CompositeInspectorConfig().setInspectors(
        new JsonSchemaInspector( new JsonInspectorConfig().setInputStream( new ByteArrayInputStream( jsonSchema.getBytes() ) ) ),
        new JsonInspector( new JsonInspectorConfig().setInputStream( new ByteArrayInputStream( json.getBytes() ) ) )
)));

metawidget.setToInspect( json );
frame.add( metawidget, BorderLayout.CENTER );
frame.setSize(500, 500);
frame.setVisible(true);

在此处输入图像描述

这没有使用 MapWidgetProcessor,因为(我想)它需要修改以支持 String 到 JSONObject 的转换。(此外,该代码块中的“NAME”变量未定义,据说需要用“elementName”替换?)

然而,所有这些都引出了几个新问题:

1)为什么'json'中的值没有映射到组件?

2)如果我没有'json'值,而只有'jsonShema',应该怎么设置?

3)为什么在架构中明确指定属性类型时代码不起作用,例如:

“名字”:{“必需”:真,“类型”:“字符串”}

4

2 回答 2

2

Metawidget 的核心原则是允许您混合搭配各种方法以适应您的架构。所以我可以分段回答这个问题。

一个基本的 SwingMetawidget:

// UI

final JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

// Metawidget

final SwingMetawidget metawidget = new SwingMetawidget();
...configure Metawidget by setting inspectors, inspection result processors, widget builders, etc...
metawidget.setToInspect( myData );
frame.add( metawidget, BorderLayout.CENTER );

要读取 JSON 类型数据和 JSON 模式,请使用 CompositeInspector:

String json = "{ \"firstname\": \"Richard\", \"surname\": \"Kennard\", \"notes\": \"Software developer\" }";
String jsonSchema = "{ properties: { \"firstname\": { \"required\": true }, \"notes\": { \"large\": true }}}";

...
metawidget.setInspector( new CompositeInspector( new CompositeInspectorConfig().setInspectors(
      new JsonInspector( new JsonInspectorConfig().setInputStream( new ByteArrayInputStream( json.getBytes() ) ) ),
      new JsonSchemaInspector( new JsonInspectorConfig().setInputStream( new ByteArrayInputStream( jsonSchema.getBytes() ) ) ) )

要映射类型,请考虑添加 TypeMappingInspectionResultProcessor:

metawidget.addInspectionResultProcessor(
    new TypeMappingInspectionResultProcessor<SwingMetawidget>(
        new TypeMappingInspectionResultProcessorConfig()
            .setTypeMapping( "foo", "bar" )
            .setTypeMapping( "abc", "def" )));

或者,可能是更好的方法,添加自定义 WidgetBuilder 来处理未知类型的小部件:

metawidget.setWidgetBuilder( new CompositeWidetBuilder( new ompositeWidgetBuilderConfig()
    .setWidgetBuilders(
        new OverriddenWidgetBuilder(), new ReadOnlyWidgetBuilder(),
        new MyWidgetBuilder(), new SwingWidgetBuilder()
    )));

MyWidgetBuilder 在哪里做类似的事情

class MyWidgetBuilder
    implements WidgetBuilder<JComponent, SwingMetawidget> {

    public JComponent buildWidget( String elementName, Map<String, String> attributes, SwingMetawidget metawidget ) {

        if ( "my.special.type".equals( attributes.get( TYPE ) ) )

            return new JSuperWidget();
        }

        // Fall through to other WidgetBuilder

        return null;
    }

默认情况下,JComponents 不会将其数据保存在任何地方。您需要为此添加类似 BeansBindingProcessor 的内容。当然 BeansBinding 只绑定到 JavaBeans。如果你想绑定到其他东西(比如 JSON 地图),你可以添加你自己的 MapWidgetProcessor:

/**
* MapWidgetProcessor uses the Metawidget's <code>toInspect</code> to retrieve/store values.
*/

public class MapWidgetProcessor
   implements AdvancedWidgetProcessor<JComponent, SwingMetawidget> {

   //
   // Public methods
   //

   @Override
   public void onStartBuild( SwingMetawidget metawidget ) {

      getWrittenComponents( metawidget ).clear();
   }

   /**
    * Retrieve the values from the Map and put them in the Components.
    */

   @Override
   public JComponent processWidget( JComponent component, String elementName, Map<String, String> attributes, SwingMetawidget metawidget ) {

      String attributeName = attributes.get( NAME );
      getWrittenComponents( metawidget ).put( attributeName, component );

      // Fetch the value...

      Map<String, Object> toInspect = metawidget.getToInspect();
      Object value = toInspect.get( attributeName );

      if ( value == null ) {
         return component;
      }

      // ...and apply it to the component. For simplicity, we won't worry about converters

      String componentProperty = metawidget.getValueProperty( component );
      ClassUtils.setProperty( component, componentProperty, value );

      return component;
   }

   @Override
   public void onEndBuild( SwingMetawidget metawidget ) {

      // Do nothing
   }

   /**
    * Store the values from the Components back into the Map.
    */

   public void save( SwingMetawidget metawidget ) {

      Map<String, Object> toInspect = metawidget.getToInspect();

      for ( Map.Entry<String,JComponent> entry : getWrittenComponents( metawidget ).entrySet() ) {

         JComponent component = entry.getValue();
         String componentProperty = metawidget.getValueProperty( component );
         Object value = ClassUtils.getProperty( component, componentProperty );

         toInspect.put( entry.getKey(), value );
      }
   }

   //
   // Private methods
   //

   /**
    * During load-time we keep track of all the components. At save-time we write them all back
    * again.
    */

   private Map<String,JComponent> getWrittenComponents( SwingMetawidget metawidget ) {

      @SuppressWarnings( "unchecked" )
      Map<String,JComponent> writtenComponents = (Map<String,JComponent>) metawidget.getClientProperty( MapWidgetProcessor.class );

      if ( writtenComponents == null ) {
         writtenComponents = CollectionUtils.newHashMap();
         metawidget.putClientProperty( MapWidgetProcessor.class, writtenComponents );
      }

      return writtenComponents;
   }
}
于 2019-09-18T21:26:15.737 回答
1

在回答新问题时:

2)然后你必须提供完整的模式。目前 jsonSchema 只有像“必需”这样的属性。像“类型”这样的属性是从 json 对象值中推断出来的。CompositeInspector 正在为您将它们合并在一起。但是,如果您只想拥有一个 JsonSchemaInspector(没有 JsonInspector,没有 CompositeInspector),那么您的 jsonSchema 将必须具有所有属性

3) 因为 'string' 是 JavaScript 类型。Java 等价物是“java.lang.String”。因此,您可以使用 TypeMappingInspectionResultProcessor(或其子类 JsonSchemaMappingInspectionResultProcessor)。这可能看起来很繁重,但请记住您正在做的事情很不寻常(在 Java 中呈现 JSON)。幸运的是,Metawidget 可以插入各种组合。

最后:“支持字符串到 JSONObject 的转换”——我不这么认为。JSONObject 是顶级概念。它基本上是一个地图。您需要绑定的各个字段仍然是原语(字符串、数字等)。所以 MapWidgetProcessor 可能是一个不错的选择。

于 2019-09-21T09:42:20.853 回答