/* * Copyright 2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.gradle.api.internal.attributes; import org.gradle.api.InvalidUserCodeException; import org.gradle.internal.Cast; import java.util.NoSuchElementException; /** * Represents an optional attribute value, as found in an attribute container. There are 3 possible cases: * <ul> * <li><i>present</i> is the default, and represents an attribute with an actual value</li> * <li><i>missing</i> used whenever an attribute is known of the {@link org.gradle.api.attributes.AttributesSchema} of a consumer, * no value was provided.</li> * <li><i>unknown</i> used whenever an attribute is unknown of the {@link org.gradle.api.attributes.AttributesSchema} of a consumer, * implying that no value was provided. It is different from the missing case in the sense that the consumer * had no chance to provide a value here.</li> * </ul> * During attribute matching, this can be used to implement various {@link org.gradle.api.attributes.AttributeMatchingStrategy strategies}. * @param <T> the type of the attribute * * @since 3.3 */ public class AttributeValue<T> { private final static AttributeValue<Object> MISSING = new AttributeValue<Object>(null) { @Override public boolean isMissing() { return true; } @Override public Object get() { throw new InvalidUserCodeException("get() should not be called on a missing attribute value"); } }; private final static AttributeValue<Object> UNKNOWN = new AttributeValue<Object>(null) { @Override public boolean isUnknown() { return true; } @Override public Object get() { throw new InvalidUserCodeException("get() should not be called on an unknown attribute value"); } }; private final T value; private AttributeValue(T value) { this.value = value; } /** * Creates a valued attribute from a non-null value. * @param value the value of the attribute * @param <T> the type of the attribute * @return a <i>present</i> attribute value */ public static <T> AttributeValue<T> of(T value) { return new AttributeValue<T>(value); } /** * Creates a missing attribute value, used to represent the fact that the attribute is known * but the consumer didn't want to express a value for it (it doesn't care). * @param <T> the type of the attribute * @return a <i>missing</i> attribute value */ public static <T> AttributeValue<T> missing() { return Cast.uncheckedCast(MISSING); } /** * Creates an unknown attribute value, used to represent the fact that the attribute is unknown * from the consumer side. Produces might want to do something differently in this case. * @param <T> the type of the attribute * @return an <i>unknown</i> attribute value */ public static <T> AttributeValue<T> unknown() { return Cast.uncheckedCast(UNKNOWN); } /** * Tells if this attribute value is present. * @return true if this attribute value is present, implying not <code>null</code>. */ public boolean isPresent() { return value != null; } /** * Returns the value of this attribute. * @return the value of this attribute. Throws an error if called on a missing or unknown attribute value. */ public T get() { if (value == null) { throw new NoSuchElementException("No value provided"); } return value; } /** * Returns true if this attribute value is unknown. * @return true if this attribute value is unknown. */ public boolean isUnknown() { return false; } /** * Returns true if this attribute value is missing. * @return true if this attribute value is missing. */ public boolean isMissing() { return false; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } AttributeValue<?> that = (AttributeValue<?>) o; return value != null ? value.equals(that.value) : that.value == null; } @Override public int hashCode() { return value != null ? value.hashCode() : 0; } }