# Interface AttributeContainer

All Superinterfaces:
  `HasAttributes`

public interface AttributeContainer extends HasAttributes
An attribute container is a container of `attributes`, which are strongly typed named entities.

Such a container is responsible for storing and getting attributes in a type safe way. In particular, attributes are strongly typed, meaning that when we get a value from the container, the returned value type is inferred from the type of the attribute. In a way, an attribute container is similar to a `Map` where the entry is a "typed String" and the value is of the string type. However, the set of methods available to the container is much more limited.

It is not allowed to have two attributes with the same name but different types in the container.

Supported attribute value types are: `String`, `Boolean`, any subtype of `Number`, and any type implementing `Named`.

Plain Java `Enum` types (that do NOT implement `Named`) are NOT supported.

Since:
  3.3

- ## Method Summary

  Modifier and Type
  Method
  Description
  `AttributeContainer`
  `addAllLater(AttributeContainer other)`
  Lazily add all attributes from `other` to this container.
  `<T> AttributeContainer`
  `attribute(Attribute<T> key, T value)`
  Sets an attribute value.
  `<T> AttributeContainer`
  `attributeProvider(Attribute<T> key, Provider<? extends T> provider)`
  Sets an attribute to have the same value as the given provider.
  `boolean`
  `contains(Attribute<?> key)`
  Tells if a specific attribute is found in this container.
  `<T> @Nullable T`
  `getAttribute(Attribute<T> key)`
  Returns the value of an attribute found in this container with the type specified by the given `key`, or `null` if this container doesn't have it.
  `boolean`
  `isEmpty()`
  Returns true if this container is empty.
  `Set<Attribute<?>>`
  `keySet()`
  Returns the set of attribute keys of this container.
  `<T extends Named>
  T`
  `named(Class<T> type, String name)`
  Creates a value of the given type for an Attribute.

  ### Methods inherited from interface HasAttributes

  `getAttributes`

- ## Method Details

  - ### keySet

    Set<Attribute<?>> keySet()
    Returns the set of attribute keys of this container.
    Returns:
      the set of attribute keys.
    Since:
      3.3

  - ### attribute

    <T> AttributeContainer attribute(Attribute<T> key, T value)
    Sets an attribute value. It is not allowed to use `null` as an attribute value.
    Type Parameters:
      `T` - the type of the attribute
    Parameters:
      `key` - the attribute key
      `value` - the attribute value
    Returns:
      this container
    Since:
      3.3

  - ### attributeProvider

    <T> AttributeContainer attributeProvider(Attribute<T> key, Provider<? extends T> provider)
    Sets an attribute to have the same value as the given provider. This attribute will track the value of the provider and query its value when this container is finalized.

    This method can NOT be used to discard the value of a property. Specifying a `null` provider will result in an `IllegalArgumentException` being thrown. When the provider has no value at finalization time, an `IllegalStateException` - regardless of whether or not a convention has been set.

    Type Parameters:
      `T` - the type of the attribute
    Parameters:
      `key` - the attribute key
      `provider` - The provider whose value to use
    Returns:
      this container
    Since:
      7.4

  - ### addAllLater

    @Incubating AttributeContainer addAllLater(AttributeContainer other)
    Lazily add all attributes from `other` to this container.

    If the given attribute container contains attribute keys that already exist in this container, the corresponding values in this container will be overwritten. Subsequent calls to `attribute(Attribute, Object)` and `attributeProvider(Attribute, Provider)` will overwrite the corresponding values from this call.

    Consider the following example:

            def color = Attribute.of("color", String)
            def shape = Attribute.of("shape", String)

            def foo = configurations.create("foo").attributes
            foo.attribute(color, "green")

            def bar = configurations.create("bar").attributes
            bar.attribute(color, "red")
            bar.attribute(shape, "square")
            assert bar.getAttribute(color) == "red"    // `color` is originally red

            bar.addAllLater(foo)
            assert bar.getAttribute(color) == "green"  // `color` gets overwritten
            assert bar.getAttribute(shape) == "square" // `shape` does not

            foo.attribute(color, "purple")
            bar.getAttribute(color) == "purple"        // addAllLater is lazy

            bar.attribute(color, "orange")
            assert bar.getAttribute(color) == "orange" // `color` gets overwritten again
            assert bar.getAttribute(shape) == "square" // `shape` remains the same

    Returns:
      this container
    Since:
      9.1.0

  - ### getAttribute

    <T> @Nullable T getAttribute(Attribute<T> key)
    Returns the value of an attribute found in this container with the type specified by the given `key`, or `null` if this container doesn't have it.

    Supplying a `null` argument is deprecated and will return `null`.

    Type Parameters:
      `T` - the type of the attribute
    Parameters:
      `key` - the attribute key
    Returns:
      the attribute value, or `null` if not found
    Since:
      3.3

  - ### isEmpty

    boolean isEmpty()
    Returns true if this container is empty.
    Returns:
      true if this container is empty.
    Since:
      3.3

  - ### contains

    boolean contains(Attribute<?> key)
    Tells if a specific attribute is found in this container.
    Parameters:
      `key` - the key of the attribute
    Returns:
      true if this attribute is found in this container.
    Since:
      3.3

  - ### named

    @Incubating <T extends Named> T named(Class<T> type, String name)
    Creates a value of the given type for an Attribute.
    Since:
      9.3.0