@Property

Collects together all the domain semantics for the property of a domain object.

API

Property.java
@interface Property {
  Class<? extends CommandDtoProcessor> commandDtoProcessor() default CommandDtoProcessor.class;     (1)
  Publishing commandPublishing() default Publishing.NOT_SPECIFIED;     (2)
  Class<? extends PropertyDomainEvent<?, ?>> domainEvent() default PropertyDomainEvent.Default.class;     (3)
  @AliasFor(annotation = DomainObject.class, attribute = "editing")
Editing editing() default Editing.NOT_SPECIFIED;     (4)
  @AliasFor(annotation = DomainObject.class, attribute = "editingDisabledReason")
String editingDisabledReason() default "";     (5)
  @AliasFor(annotation = DomainObject.class, attribute = "entityChangePublishing")
Publishing entityChangePublishing() default Publishing.NOT_SPECIFIED;     (6)
  Publishing executionPublishing() default Publishing.NOT_SPECIFIED;     (7)
  String fileAccept() default "";     (8)
  int maxLength() default -1;     (9)
  Snapshot snapshot() default Snapshot.NOT_SPECIFIED;     (10)
  Class<? extends Specification>[] mustSatisfy() default {};     (11)
  Optionality optionality() default Optionality.NOT_SPECIFIED;     (12)
  Projecting projecting() default Projecting.NOT_SPECIFIED;     (13)
  String regexPattern() default "";     (14)
  int regexPatternFlags() default 0;     (15)
  String regexPatternReplacement() default "Doesn't match pattern";     (16)
}
1 commandDtoProcessor

The CommandDtoProcessor to process this command’s DTO.

2 commandPublishing

Whether property edits, captured as Command s, should be published to CommandSubscriber s.

3 domainEvent

Indicates that changes to the property that should be posted to the org.apache.causeway.applib.services.eventbus.EventBusService event bus using a custom (subclass of) PropertyDomainEvent .

4 editing

Whether the properties of this domain object can be edited, or collections of this object be added to/removed from.

5 editingDisabledReason

If #editing() is set to Editing#DISABLED , then the reason to provide to the user as to why this property cannot be edited.

6 entityChangePublishing

When set to Publishing#DISABLED , vetoes publishing of updates for this property. Otherwise has no effect, except when using Publishing#ENABLED to override an inherited property annotation, which is a supported use-case.

7 executionPublishing

Whether Execution s (triggered property edits), should be dispatched to ExecutionSubscriber s.

8 fileAccept

For uploading Blob or Clob , optionally restrict the files accepted (eg .xslx ).

9 maxLength

The maximum entry length of a field.

10 snapshot

Indicates whether the property should be included or excluded from mementos.

11 mustSatisfy

The Specification (s) to be satisfied by this property.

12 optionality

Whether this property is optional or is mandatory (ie required).

13 projecting

If set to Projecting#PROJECTED projected , then indicates that the owner of this property is a view model which is a projection of some other entity, and that the property holds a reference to that "underlying".

14 regexPattern

Regular expression pattern that a value should conform to, and can be formatted as.

15 regexPatternFlags

Pattern flags, as per java.util.regex.Pattern#compile(String, int) .

16 regexPatternReplacement

Replacement text for the pattern in generated error message.

Members

commandDtoProcessor

The CommandDtoProcessor to process this command’s DTO.

The processor itself is used by ContentMappingServiceForCommandDto and ContentMappingServiceForCommandsDto to dynamically transform the DTOs.

commandPublishing

Whether property edits, captured as Command s, should be published to CommandSubscriber s.

domainEvent

Indicates that changes to the property that should be posted to the org.apache.causeway.applib.services.eventbus.EventBusService event bus using a custom (subclass of) PropertyDomainEvent .

Subscribers of this event can interact with the business rule checking (hide, disable, validate) and its modification (before and after).

For example:

public static class StartDateChanged extends PropertyDomainEvent { ... }

@Property(domainEvent=StartDateChanged.class)
public LocalDate getStartDate() { ...}

This subclass must provide a no-arg constructor; the fields are set reflectively.

editing

Whether the properties of this domain object can be edited, or collections of this object be added to/removed from.

Note that non-editable objects can nevertheless have actions invoked upon them.

editingDisabledReason

If #editing() is set to Editing#DISABLED , then the reason to provide to the user as to why this property cannot be edited.

If left empty (default), no reason is given.

entityChangePublishing

When set to Publishing#DISABLED , vetoes publishing of updates for this property. Otherwise has no effect, except when using Publishing#ENABLED to override an inherited property annotation, which is a supported use-case.

Relates to DomainObject#entityChangePublishing() , which controls whether entity-change-publishing is enabled for the corresponding entity type.

executionPublishing

Whether Execution s (triggered property edits), should be dispatched to ExecutionSubscriber s.

fileAccept

For uploading Blob or Clob , optionally restrict the files accepted (eg .xslx ).

The value should be of the form "file_extension|audio/|video/|image/*|media_type".

Note that this does not prevent the user from uploading some other file type; rather it merely defaults the file type in the file open dialog.

maxLength

The maximum entry length of a field.

The default value ( -1 ) indicates that no maxLength has been specified.

this will usually be supplemented by a JDO or JPA-specific annotation to indicate length of the column in the table to whic the entity is mapped.

snapshot

Indicates whether the property should be included or excluded from mementos.

To ensure that the property is actually not persisted in the objectstore, also annotate with the JDO annotation javax.jdo.annotations.NotPersistent

mustSatisfy

The Specification (s) to be satisfied by this property.

If more than one is provided, then all must be satisfied (in effect "AND"ed together).

optionality

Whether this property is optional or is mandatory (ie required).

this will usually be supplmented by a JDO or JPA-specific annotation to specify the nullability of the corresponding column in the table to which the owning entity is mapped.

projecting

If set to Projecting#PROJECTED projected , then indicates that the owner of this property is a view model which is a projection of some other entity, and that the property holds a reference to that "underlying".

This is used to automatically redirect any bookmarks to the view model (projection) to instead be directed at the underlying entity.

Only one such property should be marked as being a projection with a view model.

regexPattern

Regular expression pattern that a value should conform to, and can be formatted as.

regexPatternFlags

Pattern flags, as per java.util.regex.Pattern#compile(String, int) .

The default value, 0 , means that no flags have been specified.

regexPatternReplacement

Replacement text for the pattern in generated error message.

Examples

For example:

@DomainObject
public class Customer {
    public static class EmailSpecification extends AbstractSpecification<String> {
        public String satisfiesSafely(String proposed) {
            return EmailUtil.ensureValidEmail(proposed);    (1)
        }
    }
    @javax.jdo.annotations.Column(allowsNull="true")                (2)
    @Property(
        maxLength=30,
        mustSatisfy=EmailSpecification.class,
        regexPattern = "(\\w+\\.)*\\w+@(\\w+\\.)+[A-Za-z]+",
        regexPatternFlags=Pattern.CASE_INSENSITIVE
    )
    public String getEmailAddress() { /* ... */ }
    public void setEmailAddress(String emailAddress) { /* ... */ }
    ...
}
1 the (fictitious) EmailUtil.ensureValid(…​) (omitted for brevity) returns a string explaining if an email is invalid
2 generally use instead of the @Property#optionality attribute

The annotation is one of a handful (others including @Collection, @CollectionLayout and @PropertyLayout) that can also be applied to the field, rather than the getter method. This is specifically so that boilerplate-busting tools such as Project Lombok can be used.

Usage Notes

Mandatory vs optional

By default, Apache Causeway assumes that all properties of an domain object or view model are required (mandatory). The optionality() attribute allows this to be relaxed. The attribute is also supported for parameters.

That said, properties are most commonly defined on persistent domain objects (entities), in which case the JDO @Column should be specified. Apache Causeway can infer the maxLength directly from the equivalent @Column#length() annotation.

That said, properties are most commonly defined on persistent domain objects (entities), in which case the JDO @Column will in any case need to be specified. Apache Causeway can infer the optionality semantic directly from the equivalent @Column#allowsNull() annotation/attribute.

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @javax.jdo.annotations.Column(allowsNull="true")
    @Getter @Setter
    private String middleInitial;

    // ...
}

In this case there is no need for the @Property#optionality attribute.

Mismatched defaults

If the @Column#allowsNull attribute is omitted and the `@Property#optionality() attribute is also omitted, then note that Causeway' defaults and JDO’s defaults differ. Specifically, Causeway always assumes properties are mandatory, whereas JDO specifies that primitives are mandatory, but all reference types are optional.

When Apache Causeway initializes it checks for these mismatches during its metamodel validation phase, and will fail to boot ("fail-fast") if there is a mismatch. The fix is usually to add the @Column#allowsNull() annotation/attribute.

Superclass inheritance type

There is one case (at least) it may be necessary to annotate the property with both @Column#allowsNull and also @Property#optionality(). If the property is logically mandatory and is in a subclass, but the mapping of the class hierarchy is to store both the superclass and subclass(es) into a single table (ie a "roll-up" mapping using javax.jdo.annotations.InheritanceStrategy#SUPERCLASS_TABLE), then JDO requires that the property is annotated as @Column#allowsNull="true": its value will be not defined for other subclasses.

In this case we therefore require both annotations.

@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public abstract class PaymentMethod {
    ...
}
@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE)
public class CreditCardPaymentMethod extends PaymentMethod {

    private String cardNumber;
    @javax.jdo.annotations.Column(allowsNull="true")
    @Property(optionality=Optionality.MANDATORY)
    public String getCardNumber() { return this.cardNumber; }
    public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
    ...
}

Alternatively, you could rely on the fact that Apache Causeway never looks at fields (whereas JDO does) and move the JDO annotation to the field:

@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE)
public class CreditCardPaymentMethod extends PaymentMethod {

    @javax.jdo.annotations.Column(allowsNull="true")
    private String cardNumber;

    public String getCardNumber() { return this.cardNumber; }
    public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }

    // ...
}

However this at first glance this might be read as meaning that the property is optional whereas Apache Causeway' default (required) applies.

Non-persistent properties

Of course, not every property is persistent (it could instead be derived), and neither is every domain object an entity (it could be a view model). For these non persistable properties the optionality attribute is still required.

For example:

public class Customer {

    @javax.jdo.annotation.NotPersistent             (1)
    @Property(optionality=Optionality.OPTIONAL)
    public String getFullName() {                   (2)
        // ...
    }
    public void setFullName(String fullName) {      (3)
        // ...
    }

    // ...
}
1 a non persisted (derived) property
2 implementation would most likely derive full name from constituent parts (eg first name, middle initial, last name)
3 implementation would most likely parse the input and update the constituent parts

The attribute has no meaning for a primitive type such as int: primitives will always have a default value (e.g. zero). If optionality is required, then use the corresponding wrapper class (e.g. java.lang.Integer) and annotate with Parameter#optionality() as required.

The values for the attribute are simply OPTIONAL or MANDATORY.

It is also possible to specify optionality using @Nullable annotation.

Editing

The editing() element can be used to prevent a property from being modified or cleared, ie to make it read-only.

The related editingDisabledReason() element specifies a hard-coded reason why the property cannot be modified directly.

Whether a property is enabled or disabled depends upon these factors:

  • whether the domain object has been configured as immutable through the @DomainObject#editing() element

  • else (that is, if the domain object’s editability is specified as being AS_CONFIGURED), then the value of the 'causeway.applib.annotation.domain-object.editing' configuration property.

    If set to false, then the object’s properties (and collections) are not editable

  • else, the value of the @Property(editing=…​) attribute itself

  • else, the result of invoking any supporting disable…​() supporting methods

Thus, to make a property read-only even if the object would otherwise be editable, use:

import lombok.Getter;
import lombok.Setter;

public class Customer {
    @Property(
        editing=Editing.DISABLED,
        editingDisabledReason =
            "The credit rating is derived from multiple factors"
    )
    @Getter @Setter
    private int initialCreditRating;
}

Maximum (string) length

The maxLength() attribute applies only to String properties, indicating the maximum number of characters that the user may enter (for example in a text field in the UI). The attribute It is ignored if applied to properties of any other type.

That said, properties are most commonly defined on persistent domain objects (entities), in which case the JDO @Column will in any case need to be specified. Apache Causeway can infer the maxLength semantic directly from the equivalent @Column#length() annotation/attribute.

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @javax.jdo.annotations.Column(length=30)
    @Getter @Setter
    private String firstName;

    // ...
}

In this case there is therefore no need for the @Property#maxLength attribute.

Non-persistent properties

Of course, not every property is persistent (it could instead be derived), and neither is every domain object an entity (it could be a view model). For these non persistable properties the maxLength attribute is still required.

For example:

public class Customer {

    @javax.jdo.annotation.NotPersistent                         (1)
    @Property(maxLength=100)
    public String getFullName() { /* ... */ }                   (2)
    public void setFullName(String fullName) { /* ... */ }      (3)
    ...
}
1 a non persisted (derived) property
2 implementation would most likely derive full name from constituent parts (eg first name, middle initial, last name)
3 implementation would most likely parse the input and update the constituent parts

See also

This attribute can also be applied to parameters.

Declarative validation

The mustSatisfy() element allows arbitrary validation to be applied to properties using an (implementation of a) org.apache.causeway.applib.spec.Specification object. The attribute is also supported on parameters.

The specification implementations can (of course) be reused between properties and parameters.

The Specification is consulted during validation, being passed the proposed value. If the proposed value fails, then the value returned is the used as the invalidity reason.

For example:

public class StartWithCapitalLetterSpecification
        extends AbstractSpecification<String> {            (1)
    public String satisfiesSafely(String proposed) {
        return "".equals(proposed)
            ? "Empty string"
            : !Character.isUpperCase(proposed.charAt(0))
                ? "Does not start with a capital letter"
                : null;
    }
}
1 the AbstractSpecification class conveniently handles type-safety and dealing with null values.

where:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @Property(mustSatisfy=StartWithCapitalLetterSpecification.class)
    @Getter @Setter
    private String firstName;

    // ...
}

It is also possible to provide translatable reasons. Rather than implement Specification, instead implement Specification2 which defines the API:

public interface Specification2 extends Specification {
    public TranslatableString satisfiesTranslatable(Object obj); (1)
}
1 Return null if specification satisfied, otherwise the reason as a translatable string

With Specification2 there is no need to implement the inherited satifies(Object); that method will never be called.

Projections

A common use case for view models is to act as a projection of some underlying entity, to decorate that entity with additional behaviour (or remove existing behaviour) for some particular business context.

Very often the object that is of interest to the end-user is the underlying entity, not the view model per se. If the view model is displayed within a table (on a home page, say), then when the user clicks the entity/icon link for the view model, they will in fact want to drill-down to the underlying entity and skip the view model completely.

The projecting() element allows the view model to indicate which of its properties holds a reference to the underlying entity of which it is a projection.

For example:

@DomainObject(nature=VIEW_MODEL)
public InvoiceSummary {

    @Property(
        projecting = Projecting.PROJECTED,  (1)
        hidden = Where.EVERYWHERE           (2)
    )
    @Getter @Setter
    private Invoice invoice;

    public LocalDate getDueDate() {         (3)
        return invoice.getDueDate();
    }

    ...
}
1 indicates that this property holds a reference to the underlying entity
2 the underlying entity is typically (though not necessarily) hidden
3 typical implementation of the properties of the underlying entity that are being projected in the view model.

Domain events

Whenever a domain object (or list of domain objects) is to be rendered, the framework fires off multiple domain events for every property, collection and action of the domain object. In the cases of the domain object’s properties, the events that are fired are:

  • hide phase: to check that the property is visible (has not been hidden)

  • disable phase: to check that the property is usable (has not been disabled)

  • validate phase: to check that the property’s arguments are valid (to modify/clear its value)

  • pre-execute phase: before the modification of the property

  • post-execute: after the modification of the property

Subscribers subscribe through the EventBusService and can influence each of these phases.

By default the event raised is PropertyDomainEvent.Default. For example:

import lombok.Getter;
import lombok.Setter;

public class ToDoItem {

    @Property()
    @Getter @Setter
    private LocalDate dueBy;

    // ...
}

The domainEvent() element allows a custom subclass to be emitted allowing more precise subscriptions (to those subclasses) to be defined instead.

For example:

import lombok.Getter;
import lombok.Setter;

public class ToDoItem {

    public static class DueByChangedEvent
        extends PropertyDomainEvent<ToDoItem, LocalDate> { }  (1)

    @Property(domainEvent=ToDoItem.DueByChangedEvent)
    @Getter @Setter
    private LocalDate dueBy;

    // ...
}
1 inherit from PropertyDomainEvent<T,P> where T is the type of the domain object being interacted with, and P is the type of the property (LocalDate in this example)

The benefit is that subscribers can be more targeted as to the events that they subscribe to.

The framework provides a no-arg constructor and will initialize the domain event using (non-API) setters rather than through the constructor. This substantially reduces the boilerplate required in subclasses because no explicit constructor is required.

Subscribers

Subscribers (which must be domain services) subscribe to events posted through the EventBusService.

Subscribers can be either coarse-grained (if they subscribe to the top-level event type):

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class SomeSubscriber {

    @EventListener(PropertyDomainEvent.class)
    public void on(PropertyDomainEvent ev) {
        // ...
    }
}

or can be fine-grained (by subscribing to specific event subtypes):

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class SomeSubscriber {

    @EventListener(ToDoItem.DueByChangedEvent.class)
    public void on(ToDoItem.DueByChangedEvent ev) {
        // ...
    }
}

The subscriber’s method is called (up to) 5 times:

  • whether to veto visibility (hide)

  • whether to veto usability (disable)

  • whether to veto execution (validate)

  • steps to perform prior to the property being modified

  • steps to perform after the property has been modified.

The subscriber can distinguish these by calling ev.getEventPhase(). Thus the general form is:

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class SomeSubscriber {

    public void on(PropertyDomainEvent ev) {
        switch(ev.getEventPhase()) {

            case HIDE:                      (1)
                break;
            case DISABLE:                   (2)
                break;
            case VALIDATE:                  (3)
                break;

            case EXECUTING:
                break;
            case EXECUTED:
                break;
        }
    }
}
1 call ev.hide() or ev.veto("") to hide the property
2 call ev.disable("…​") or ev.veto("…​") to disable the property
3 call ev.invalidate("…​") or ev.veto("…​") if proposed new value for property is invalid

It is also possible to abort the transaction during the executing or executed phases by throwing an exception. If the exception is a subtype of RecoverableException then the exception will be rendered as a user-friendly warning (eg Growl/toast) rather than an error.

Default, Doop and Noop events

If the domainEvent() element is not explicitly specified (is left as its default value, PropertyDomainEvent.Default), then the framework will, by default, post an event.

If this is not required, then the causeway.applib.annotation.property.domain-event.post-for-default configuration property can be set to "false"; this will disable posting.

On the other hand, if the domainEvent has been explicitly specified to some subclass, then an event will be posted. The framework provides PropertyDomainEvent.Doop as such a subclass, so setting the domainEvent attribute to this class will ensure that the event to be posted, irrespective of the configuration property setting.

And, conversely, the framework also provides PropertyDomainEvent.Noop; if domainEvent attribute is set to this class, then no event will be posted.

Raising events programmatically

Normally events are only raised for interactions through the UI. However, events can be raised programmatically either by calling the EventBusService API directly, or by emulating the UI by wrapping the target object using the WrapperFactory domain service.

Execution Publishing

The executionPublishing() element determines whether and how a property edit is published via the registered implementation of ExecutionSubscriber.

A common use case is to notify external "downstream" systems of changes in the state of the Apache Causeway application.

The causeway.applib.annotation.property.execution-publishing configuration property is used to determine the whether the property edits are published:

  • all

    all property edits are published

  • none

    no property edits are published

If there is no configuration property in application.properties then publishing is automatically enabled.

This default can be overridden on an property-by-property basis; if executionPublishing() is set to ENABLED then the property edit is published irrespective of the configured value; if set to DISABLED then the property edit is not published, again irrespective of the configured value.

For example:

import lombok.Getter;
import lombok.Setter;

public class Order {

    @Property(executionPublishing=Publishing.ENABLED)    (1)
    @Getter @Setter
    private int quantity;

    // ...
}
1 because set to enabled, will be published irrespective of the configured value.

Command Processing

Every property edit (and action invocation for that matter) is normally reified into a concrete Command object, basically a wrapper around the XML invocation Command schema that also captures some timing metrics about the execution as well as the outcome.

The main uses cases are:

  • as a means to allow asynchronous child commands to be executed, using the WrapperFactory service;

  • as a means to audit (persist) commands, by implementing the CommandSubscriber SPI.

    The Command Log extension does provide such an implementation.

    Another option to achieve this is to use the ExecutionSubscriber SPI.

The commandPublishing() element can be used to explicitly enable or disable command publishing for the property edit.

CommandDtoProcessor implementations

The commandDtoProcessor() element allows an implementation of CommandDtoProcessor to be specified. This interface has the following API:

public interface CommandDtoProcessor {
    CommandDto process(             (1)
            CommandDto dto);        (2)
}
1 The returned CommandDto. This will typically be the CommandDto passed in, but may be supplemented in some way.
2 The CommandDto obtained already from the Command.

This interface is used by the framework-provided implementations of ContentMappingService for the REST API, allowing Commands implementations that also implement CommandWithDto to be further customised as they are serialized out. The primary use case for this capability is in support of primary/secondary replication.

  • on the primary, Commands are serialized to XML. This includes the identity of the target object and the argument values of all parameters.

    Any Blobs and Clobs are deliberately excluded from this XML (they are instead stored as references). This is to prevent the storage requirements for Command from becoming excessive. A CommandDtoProcessor can be provided to re-attach blob information if required.

  • replaying Commands requires this missing parameter information to be reinstated. The CommandDtoProcessor therefore offers a hook to dynamically re-attach the missing Blob or Clob argument.

As a special case, returning null means that the command’s DTO is effectively excluded when retrieving the list of commands. If replicating from master to slave, this effectively allows certain commands to be ignored. The CommandDtoProcessor.Null class provides a convenience implementation for this requirement.

If commandDtoProcessor() is specified, then commandPublishing() is assumed to be ENABLED.

Example

For an example, see Action#command().

Regular expressions

There are three elements related to enforcing regular expressions:

  • The regexPattern() element validates the contents of any string property with respect to a regular expression pattern. It is ignored if applied to properties of any other type.

  • The regexPatternFlags() element specifies flags that modify the handling of the pattern. The values are those that would normally be passed to java.util.regex.Pattern#compile(String,int).

  • The regexPatternReplacement() attribute specifies the error message to show if the provided argument does not match the regex pattern.

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @Property(
        regexPattern = "(\\w+\\.)*\\w+@(\\w+\\.)+[A-Za-z]+",
        regexPatternFlags=Pattern.CASE_INSENSITIVE,
        regexPatternReplacement =
            "Must be valid email address (containing a '@') symbol"   (1)
    )
    @Getter @Setter
    private String email;
}
1 Note that there is currently no i18n support for this phrase.

See also

This attribute can also be specified for parameters.

Snapshotting state

The snapshot() element indicates whether the property should be included/excluded from any snapshots generated by the XmlSnapshotService.

For example:

import lombok.Getter;
import lombok.Setter;

public class Order {

    @Property(snapshot=EXCLUDED)
    @Getter @Setter
    private Order previousOrder;

    // ...
}

If the property is derived, then providing only a "getter" will also work:

public class Order {
    public Order getPreviousOrder() {...}
    ...
}

Uploading Blobs and Clobs

The fileAccept() element applies only to Blob or Clob parameters, indicating the type of file to accept when uploading a new value. The attribute is also supported on parameters.

For example:

import lombok.Getter;
import lombok.Setter;

public class ScannedDocument {

    @Property(fileAccept="image/*")                 (1)
    @Getter @Setter
    private Blob scannedImage;

}
1 as per reference docs, either a media type (such as image/*) or a file type extension (such as .png).

Hiding properties

Properties can be hidden at the domain-level, indicating that they are not visible to the end-user.

It is also possible to use @Property#hidden() to hide an action at the domain layer.

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @Property(hidden=Where.EVERYWHERE)
    @Getter @Setter
    private int internalId;

    // ...
}

The acceptable values for the where parameter are:

  • Where.EVERYWHERE or Where.ANYWHERE

    The property should be hidden everywhere.

  • Where.ANYWHERE

    Synonym for everywhere.

  • Where.OBJECT_FORMS

    The property should be hidden when displayed within an object form.

  • Where.PARENTED_TABLES

    The property should be hidden when displayed as a column of a table within a parent object’s collection.

  • Where.STANDALONE_TABLES

    The property should be hidden when displayed as a column of a table showing a standalone list of objects, for example as returned by a repository query.

  • Where.ALL_TABLES

    The property should be hidden when displayed as a column of a table, either an object’s * collection or a standalone list. This combines PARENTED_TABLES and STANDALONE_TABLES.

  • Where.NOWHERE

    The property should not be hidden, overriding any other metadata/conventions that would normally cause the property to be hidden.

For example, if a property is annotated with @Title, then normally this should be hidden from all tables. Annotating with @Property(where=Where.NOWHERE) overrides this.

The RestfulObjects viewer has only partial support for these Where enums.