Class AbstractConfigurationObject

java.lang.Object
com.vaadin.flow.component.map.configuration.AbstractConfigurationObject
All Implemented Interfaces:
Serializable
Direct Known Subclasses:
Configuration, Feature, Fill, ImageStyle, Layer, SimpleGeometry, Source, Stroke, Style, TextStyle, View

public abstract class AbstractConfigurationObject extends Object implements Serializable
Base class for all map configuration objects that represent an OL class. The class provides functionality to support the synchronization mechanism between server and client, such as:

When adding new API to the Map component using this class, there are several rules to follow:

  • Implement getType() to return a unique type name. This type name is used by the client-side synchronization to determine which OpenLayers class to instantiate for objects of this type. See META-INF/resources/frontend/vaadin-map/synchronization/index.js for how the synchronization resolves type names.
  • Every setter must call markAsDirty() in order to mark this object as changed, and to trigger a change event to schedule a sync. of this change. See View.setCenter(Coordinate) for an example.
  • Setters for nested objects must keep track of nested references using addChild(AbstractConfigurationObject) and removeChild(AbstractConfigurationObject). See Configuration.setView(View) for an example.
  • When using collection properties, do not expose the collection directly for manipulation, as manipulating the collection does not mark the object as changed, and does not trigger a change event. Instead add methods for manipulating the collection, and keep track of objects being added / removed from the collection using addChild(AbstractConfigurationObject) and removeChild(AbstractConfigurationObject). See Configuration.addLayer(Layer) and Configuration.removeLayer(Layer) for an example.
  • For properties that contain nested configuration objects, or collections, use the Jackson JsonIdentityInfo and JsonIdentityReference annotations to only serialize the ID of the object. See Configuration.getLayers() for an example.
  • For properties that are not needed on the client-side, or do not have a pendant in the OpenLayers API, use the Jackson JsonIgnore annotation to reduce the JSON payload that is sent to the client on each synchronization, and to prevent possible errors by passing unrecognized options to the OpenLayers API. See View.getExtent() for an example.
  • Not every class used in configuring the map necessarily needs to extend from AbstractConfigurationObject. Using this class is only necessary if an object is supposed to be modified by the developer (e.g. a Layer should be modifiable to change its visibility). If the object is small, or can be immutable, it might make sense to not extend from this class, and instead force the developer to create new instances instead. See Coordinate for an example, where making coordinates modifiable / synchronizable would just add more overhead, and where it's reasonable to just create new instances instead.
See Also:
  • Field Details

  • Constructor Details

    • AbstractConfigurationObject

      public AbstractConfigurationObject()
  • Method Details

    • getId

      public String getId()
    • setId

      public void setId(String id)
    • getType

      public abstract String getType()
      The unique type name of this class. Used by the client-side synchronization mechanism to determine which OpenLayers class to synchronize into.
    • markAsDirty

      protected void markAsDirty()
      Marks this configuration object as dirty / as changed, so that it will be picked up for the next synchronization.

      This also triggers notifyChange() to notify observers that a change happened.

    • deepMarkAsDirty

      protected void deepMarkAsDirty()
      Marks this configuration object, as well as all nested objects, as dirty / as changed, so that the full nested hierarchy will be picked up for the next synchronization.

      Unlike markAsDirty() this does not trigger notifyChange(). Currently, there are limited use-cases for this method, and in all of them a change event, or a map synchronization, will already be triggered through other means. Triggering a change event in this method would lead to recursively triggering change events from all nested objects, each of which would then bubble up through the hierarchy again, which seems wasteful and is unnecessary at the moment. If another use-case comes up in the future, consider just calling notifyChange() manually after this method.

    • addChild

      protected void addChild(AbstractConfigurationObject configurationObject)
      Adds a nested object reference to keep track of. This adds the object to an internal set that is used when collecting changed / dirty objects for the next synchronization, and adds a change listener to the nested object in order to let change events bubble up the configuration hierarchy. This method also automatically marks this object as dirty, and triggers a change event to notify observers about changes. One special behavior of this method is that it will trigger a full sync of the nested hierarchy that was added, in order to ensure that all added references can be resolved on the client-side.
    • addNullableChild

      protected void addNullableChild(AbstractConfigurationObject configurationObject)
      Convenience wrapper for addChild(AbstractConfigurationObject) that allows configurationObject to be a null reference.
    • removeChild

      protected void removeChild(AbstractConfigurationObject configurationObject)
      Removes a nested object reference from tracking. This removes the object from the internal set used for collecting changes, and removes the change listener on it. This method also automatically marks this object as dirty, and triggers a change event to notify observers about changes.
    • notifyChange

      protected void notifyChange()
      Notifies observers that this object has changed. Usually there is no need to use this directly, instead markAsDirty(), addChild(AbstractConfigurationObject), or removeChild(AbstractConfigurationObject) should be used.
    • notifyChange

      protected void notifyChange(PropertyChangeEvent event)
      Same behavior as notifyChange(), can be used as a shortcut to relay events from nested objects.
    • addPropertyChangeListener

      protected void addPropertyChangeListener(PropertyChangeListener listener)
      Adds a change listener to the object. This will be called on any change made to the object that results in a call to notifyChange().
    • removePropertyChangeListener

      protected void removePropertyChangeListener(PropertyChangeListener listener)
      Removes a change listener from the object.
    • update

      protected void update(Runnable updater, boolean trackObjectChanges)
      Updates an object using a Runnable that executes code for manipulating this object. The method has a parameter for controlling whether the manipulations from the runnable should trigger change events, and mark the object as dirty. This can be useful to prevent change events and resulting synchronizations when updating the server-side with state from the client. See View.updateInternalViewState(Coordinate, double, double, Extent) for an example.
      Parameters:
      updater - a runnable containing code to manipulate this object
      trackObjectChanges - whether to enable or disable change tracking when executing the runnable
    • collectChanges

      protected void collectChanges(Consumer<AbstractConfigurationObject> changeCollector)
      Collects all changed objects from a configuration hierarchy. If this object has been marked as dirty / changed, then it will be collected, and then marked as non-dirty / unchanged. Additionally, all nested objects are also checked, resulting in a recursive collection of changes. It is important that nested objects are collected first, so that during the client-side sync these instances are created and updated first, before higher-level instances that reference them.