The Properties module provides facilities to extend existing entities with custom properties, with optional revision tracking.
Dependency
<dependencies>
<dependency>
<groupId>across-standard-modules</groupId>
<artifactId>properties-module</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
</dependencies>
Configuration
Installers
In order to extend existing entities with properties, the tables for these properties have to be installed. The client application can do this by registering installers that extend from EntityPropertiesInstaller or RevisionBasedEntityPropertiesInstaller.
Repositories
The Properties module offers a base implementation of EntityPropertiesRepository that can be extended with a typed implementation.
Services
The client application should then extend either AbstractEntityPropertiesService or AbstractRevisionBasedEntityPropertiesService. These services can then be wired into the entity services and used as described below.
Registries
The entities with properties should have a registry class extending from EntityPropertiesRegistry. Registries are classes that contain a map for the properties added to a specific entity. For example, a User entity class can have a corresponding UserPropertiesRegistry class.
Properties configuration
The properties for a specific entity are configured in a configuration class extending from AbstractEntityPropertiesConfiguration. This class will specify the entity class, table name, the identifying column name and wire all classes extended as described above.
Property registration
The client application should register the properties during application startup as follows:
@PostConstruct
protected void registerProperties() {
userPropertiesRegistry.register( currentModule, "registration_code", String.class );
}
This snippet should be contained in a configuration class and autowire the current module and the specific EntityPropertiesRegistry for which this configuration is happening:
@Autowired
@Module(AcrossModule.CURRENT_MODULE)
private AcrossModule currentModule;
@Autowired
private UserPropertiesRegistry userPropertiesRegistry;
This registry contains the definition of the property key to its implementation class and optionally a default value. See EntityPropertiesRegistry for all available options.
Defaults
The Properties module supports simple types and parametrized types for registries. When registering a mapping, the client application can supply a default value. These defaults should not be changed by client code. In order to enforce this, the Properties module uses PropertyFactory from the Foreach common libraries as a way to construct these defaults. TypeDescriptors (from Spring) are used to describe the parameter types.
Examples:
// A SingletonPropertyFactory used for an enum:
userPropertiesRegistry.register( currentModule, "enum_property", AnEnum.class,
SingletonPropertyFactory.<String, AnEnum>forValue( AnEnum.SOME_VALUE ) );
// An anonymous implementation of PropertyFactory for a Set of Foo (which is an entity):
userPropertiesRegistry.register( currentModule,
"userFoo",
TypeDescriptor.collection( Set.class, TypeDescriptor.valueOf( Foo.class ) ),
new PropertyFactory<String, Object>()
{
@Override
public Object create( PropertyTypeRegistry registry, String propertyKey ) {
return new HashSet<Foo>();
}
}
);
Usage
If the Properties module is configured correctly and the services are wired, the properties of a specific entity can be read and set as follow:
Foo foo = new Foo( "aFoo" );
UserProperties userProperties = userPropertiesService.getProperties( userId );
Set<Foo> foos = userProperties.getValue( "userFoo" );
foos.add( foo );
userPropertiesService.saveProperties( userProperties );
Note that properties should always be saved after updating.