2 回答
TA贡献1770条经验 获得超3个赞
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;
}
默认情况下,JComponent 不会将其数据保存在任何地方。您需要为此添加类似 BeansBindingProcessor 的内容。当然,BeansBinding 只绑定到 JavaBean。如果你想绑定到其他东西(比如 JSON Map),你可以添加你自己的 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;
}
TA贡献1869条经验 获得超4个赞
回答新问题:
2)然后你必须提供完整的模式。目前 jsonSchema 仅具有“required”等属性。“type”等属性是从 json 对象值推断出来的。CompositeInspector 正在为您将它们合并在一起。但是如果你只想有一个 JsonSchemaInspector (没有 JsonInspector,没有 CompositeInspector),那么你的 jsonSchema 必须拥有所有属性
3)因为“string”是JavaScript类型。Java 等效项是“java.lang.String”。因此,您可以使用 TypeMappingInspectionResultProcessor (或其子类 JsonSchemaMappingInspectionResultProcessor)。这可能看起来很繁重,但请记住您正在做的事情非常不寻常(在 Java 中渲染 JSON)。幸运的是,Metawidget 可以插入各种组合。
最后:“支持 String 到 JSONObject 转换” - 我不这么认为。JSONObject 是顶层概念。它基本上是一张地图。您需要绑定的各个字段仍然是基元(字符串、数字等)。所以 MapWidgetProcessor 可能是一个不错的选择。
添加回答
举报