I've been asked to provide a complete example of using Metawidget to bridge the gap between an annotation-based, Java EE back-end and a JavaScript, Bootstrap 3 front-end.
This requires metadata to be fed from the 'Java world' into the 'JavaScript world'. Metawidget excels at this, using a process it calls 'remote inspection'. Metawidget's five-stage pipeline is designed to be split across multiple tiers and disparate architectures.
First, create the annotated Java object. We'll use Metawidget's built-in annotations here, but you can of course use JPA annotations, Hibernate Validator annotations etc.
public class Person {
private String mFirstname;
private String mSurname;
private int mAge;
private boolean mRetired;
@UiRequired
public String getFirstname() {...}
@UiComesAfter( "firstname" )
public String getSurname() {...}
@UiComesAfter( "surname" )
public int getAge() {...}
...other getters and setters...
}
Then, create a REST service that uses Metawidget's inspectors to inspect that object, and returns the inspection result in JSON format:
mInspector = new CompositeInspector( new CompositeInspectorConfig().setInspectors(
new PropertyTypeInspector(),
new MetawidgetAnnotationInspector()
) );
mInspectionResultProcessors = new DomInspectionResultProcessor[] {
new ComesAfterInspectionResultProcessor<Object>(),
new JsonSchemaMappingProcessor<Object>(),
new JsonTypeMappingProcessor<Object>()
};
...
// Inspect
Element inspectionResult = mInspector.inspectAsDom( null, entityClass.getName() );
for ( DomInspectionResultProcessor<Element, Object> inspectionResultProcessor : mInspectionResultProcessors ) {
inspectionResult = inspectionResultProcessor.processInspectionResultAsDom(
inspectionResult, null, null, entityClass.getName(), (String[]) null );
}
// Convert to JSON Schema
return XmlUtils.elementToJsonSchema( inspectionResult );
Finally, create a JavaScript Metawidget that uses Bootstrap 3 and calls the REST service asynchronously:
<!DOCTYPE HTML>
<html>
<head>
<link href="lib/bootstrap/css/bootstrap.min.css" type="text/css" rel="stylesheet"/>
<script src="lib/jquery/jquery.min.js"></script>
<script src="lib/bootstrap/js/bootstrap.min.js"></script>
<script src="js/metawidget-core.min.js"></script>
<script src="js/metawidget-bootstrap.min.js"></script>
</head>
<body>
<div style="width: 500px; margin: 50px auto">
<form class="form-horizontal">
<div id="metawidget">
<button class="btn btn-primary" onclick="save(); return false">Save</button>
</div>
</form>
</div>
<script type="text/javascript">
var mw = new metawidget.Metawidget( document.getElementById( 'metawidget' ), {
inspectionResultProcessors: [ function( inspectionResult, mw, toInspect, type, names ) {
var xhr = new XMLHttpRequest();
xhr.open( "GET", "rest/schema/person", true );
xhr.onreadystatechange = function() {
if ( xhr.readyState == 4 && xhr.status == 200 ) {
metawidget.util.combineInspectionResults( inspectionResult,
JSON.parse( xhr.responseText ) );
// Resume Metawidget operation
mw.buildWidgets( inspectionResult );
}
}
xhr.send();
// Return nothing to suspend Metawidget operation
} ],
addWidgetProcessors: [ new metawidget.bootstrap.widgetprocessor.BootstrapWidgetProcessor() ],
layout: new metawidget.bootstrap.layout.BootstrapDivLayout()
} );
mw.toInspect = {};
mw.buildWidgets();
function save() {
mw.getWidgetProcessor( function( widgetProcessor ) {
return widgetProcessor instanceof metawidget.widgetprocessor.SimpleBindingProcessor;
} ).save( mw );
console.log( mw.toInspect );
}
</script>
</body>
</html>
This will produce:
Here's a link to a complete Eclipse project. Feedback welcome!