Skip to content

State Model

Sample State

Let’s start with a simple state model:

/** Our contract class */
class NewsPaperContract: Contract {

    /** State definition */
    @LeanStateModel
    interface NewsPaper {
        val publisher: Party?
        val author: Party
        //...
    }
}

Targeting a Contract

In the above example the NewsPaper type is contained in a Corda Contract so there is no need to specify the contract type target for the generated ContractState. If NewsPaper was in a standalone file, we would specify the contract using LeanStateModel.contractClass:

/** Standalone state definition */
@LeanStateModel(contractClass = NewsPaperContract::class)
interface NewsPaper {
    val publisher: Party?
    val author: Party
    //...
}

or using a classname string with LeanStateModel.contractClassName:

/** Standalone state definition */
@LeanStateModel(contractClassName = "my.package.NewsPaperContract")
interface NewsPaper {
    val publisher: Party?
    val author: Party
    //...
}

Property Initializers

To add default value initializers to your contract state, use @LeanStateProperty.initializer like shown bellow:

@LeanStateModel
interface NewsPaper {
    //...
    @get:LeanStateProperty(initializer = "NewsPaperStatus.FOOBAR")
    val status: NewsPaperStatus
}

Default Participants

The default strategy used by the annotation processor scans your interface and uses members of the following types to create the default participants implementation:

  • net.corda.core.identity.Party
  • net.corda.core.identity.AbstractParty
  • net.corda.core.identity.AnonymousParty
  • java.security.PublicKey
  • Types with a proper party member, e.g. com.github.manosbatsis.vaultaire.dto.AccountParty
  • Any collection parameterised with one of the above

Overriding LinearState

If besides all other options available you still want to directly customise the overrides
for LinearState you can so it in your interface. The annotation processor will honor them by not generating its own.

/** State definition */
@LeanStateModel
interface NewsPaper: LinearState {
    val publisher: Party?
    val author: Party
    //...

    // Optional, no need to add or override explicitly
    override val linearId: UniqueIdentifier

    // Optionally override LinearState.participants  
    // if you don't want the implementation generated by default
    override val participants get() = listOfNotNull(publisher?.party, author.party)

}

Custom Table Name

To customise the generated @Table annotation use @LeanStateModel.tableName like shown bellow:

@LeanStateModel(tableName = "custom_table_name")
interface NewsPaper {
    //...
}

Custom Migration Resource

To customise the generated MappedSchema implementation for using a custom Liquibase migrationResource, use @LeanStateModel.migrationResource like shown bellow:

@LeanStateModel(migrationResource = "custom-newspaper-schema-v1.changelog-master.xml")
interface NewsPaper {
    //...
}

this will generate

Overriding QueryableState

If besides all other options available you still want to directly customise overrides for QueryableState you can do so in your interface. The annotation processor will honor them by not generating its own.

@LeanStateModel
interface NewsPaper: QueryableState {
    val publisher: Party?
    val author: Party
    //...

    // Optional, only override to use a custom implementation 
    // VS the default strategy. 
    override fun generateMappedObject(schema: MappedSchema) = NewsPaperPersistentState(
        // ...
    )

    // Only extend QueryableState and override if you don't want the implementation generated by default
    override fun supportedSchemas() = listOf(SchemaV1)

    // Only add if you explicitly implement supportedSchemas()
    object Schema
    object NSchemaV1 : MappedSchema(NewsPaperSchema::class.java, 1, listOf(NewsPaperPersistentState::class.java))

}

Property Mapping Modes

[LeanStateModel] and [LeanStateProperty] annotations allow configuration of Contract to Persistent State property mappings using one or more of the following:

  • NATIVE: Will generate PersistentState fields using the original ContractState field if possible.
  • STRINGIFY: Will generate string-based PersistentState field variants where applicable, suffixing their names with “String”.
  • EXPANDED: Will generate PersistentState fields by expanding applicable types to properties corresponding to their individual members.
// Tweak mapping modes at type level, 
// default is [PropertyMappingMode.EXPANDED],
@LeanStateModel(mappingModes = [
    PropertyMappingMode.NATIVE,
    PropertyMappingMode.STRINGIFY,
    PropertyMappingMode.EXPANDED]
)
interface NewsPaper {
    val publisher: Party?
    // Tweak modes at property level
    @LeanStateProperty(mappingModes = [
                PropertyMappingMode.STRINGIFY])
    val author: Party
    //...
}

JPA Overrides

JPA @Column annotations found in your model interface will be copied as-is, overriding the annotation processor defaults.

@LeanStateModel
interface NewsPaper {
    // Override JPA Column generation 
    @get:Column(name = "alt_title", length = 500)
    val alternativeTitle: String?
    //...
}