This is the first in what I hope to be a series of blog posts highlighting new features in the upcoming Sapphire 0.4 release.
When a property is described to a user in documentation one does it with a series of short statements that define its semantics, such as "must be specified" or "maximum value is 100". When a property is described to Sapphire one does it with a series of annotations, such as @Required or @NumericRange. This duplicate specification is a maintenance problem.
A FactsService provides a means to dynamically derive statements about property's semantics based on property's metadata. The derived facts can then be presented to the user as part of documentation, property editor information popup and in other relevant places.
A single facts service can produce multiple facts and multiple facts services can be active concurrently for a given property. FactsAggregationServices provides an easier way to consume all facts.
Sapphire includes a number of FactsService implementations.
ID | Description |
---|---|
Sapphire.FactsService.JavaTypeConstraint | Creates fact statements about Java type property's constraints by using semantical information specified by @JavaTypeConstraints annotation. |
Sapphire.FactsService.Static | Creates fact statements about property by using static content specified in @Fact and @Facts annotations. |
Sapphire.FactsService.DefaultValue | Creates fact statements about property's default value by using semantical information specified by DefaultValueService and @DefaultValue annotation. |
Sapphire.FactsService.NumericRange | Creates fact statements about numeric value property's range by using semantical information specified by @NumericRange annotation. |
Sapphire.FactsService.Required | Creates fact statements about property's optionality by using semantical information specified by @Required annotation. |
Sapphire.FactsService.ReadOnly | Creates fact statements about property's read-only state by using semantical information specified by @ReadOnly annotation. |
Sapphire.FactsService.CountConstraint | Creates fact statements about list property's count constraint by using semantical information specified by @CountConstraint annotation. |
Sapphire.FactsService.AbsolutePath | Creates fact statements about property's absolute path requirement by using semantical information specified by @AbsolutePath annotation. |
Sapphire.FactsService.MustExist | Creates fact statements about existence requirement on the entity referenced by property's value by using semantical information specified by @MustExist annotation. |
Sapphire.FactsService.NoDuplicates | Creates fact statements about value property's uniqueness constraint by using semantical information specified by @NoDuplicates annotation. |
Sapphire.FactsService.ValidFileExtensions | Creates fact statements about valid file extensions for property's value by using semantical information specified by @ValidFileExtensions annotation. |
Sapphire.FactsService.ValidFileSystemResourceType | Creates fact statements about valid file system resource type (file or folder) for property's value by using semantical information specified by @ValidFileSystemResourceType annotation. |
Sapphire.FactsService.ProjectRelativePath | Creates fact statements about property's relative to the project path requirement by using semantical information specified by @ProjectRelativePath annotation. |
Sapphire.FactsService.WorkspaceRelativePath | Creates fact statements about property's relative to the workspace path requirement by using semantical information specified by @WorkspaceRelativePath annotation. |
Example
This screen capture shows user experience with some of the provided FactsService implementation. See if you can match facts in the screen capture to service implementations above.
Adopters can provide custom FactService implementations either globally using Sapphire extension system or at the property level using @Service annotation.
Example
A simple global FactsService implementation that is triggered by a hypothetical @Since property annotation.
public class SinceVersionFactsService extends FactsService
{
@Override
protected void facts( List facts )
{
Since since = property().getAnnotation( Since.class );
facts.add( "Since version " + since.version() + "." );
}
public static class Factory extends ModelPropertyServiceFactory
{
@Override
public boolean applicable( IModelElement element,
ModelProperty property,
Class<? extends ModelPropertyService> service )
{
return property.hasAnnotation( Since.class );
}
@Override
public ModelPropertyService create( IModelElement element,
ModelProperty property,
Class<? extends ModelPropertyService> service )
{
return new SinceVersionFactsService();
}
}
}
The service implementation is registered in META-INF/sapphire-extension.xml file.
<extension xmlns="http://www.eclipse.org/sapphire/xmlns/extension">
<model-property-service>
<id>Example.SinceVersionFactsService</id>
<type>org.eclipse.sapphire.services.FactsService</type>
<factory>example.SinceVersionFactsService$Factory</factory>
</model-property-service>
</extension>
Facts can also be statically specified for a given property by using @Fact annotation. Use @Facts annotation to specify multiple facts. The facts contained in these annotations are surfaced by an included FactsService implementation (id:Sapphire.FactsService.Static).
Example
// *** ExampleOne ***
@Fact( statement = "Important fact.")
ValueProperty PROP_EXAMPLE_ONE = new ValueProperty( TYPE, "ExampleOne" );
Value getExampleOne();
void setExampleOne( String value );
// *** ExampleMultiple ***
@Facts( { @Fact( statement = "First important fact." ), @Fact( statement = "Second important fact." ) } )
ValueProperty PROP_EXAMPLE_MULTIPLE = new ValueProperty( TYPE, "ExampleMultiple" );
Value getExampleMultiple();
void setExampleMultiple( String value );
Please direct your comments and questions to Sapphire adopter forum.