/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 gobblin.util; import lombok.AccessLevel; import lombok.AllArgsConstructor; import com.google.common.base.Optional; /** * Represents a value of one of two possible types. Similar to Scala's Either. * Each instance of {@link Either} is of type {@link Left} or {@link Right} depending of the class of its value. * * <p> * This class is useful when a class has two different states, each of which depends on a variable of a different * type (for example a String name or Numeric id). While the normal pattern is to have two variables, only one of * which is set, or two Optionals, only one of which is present, that pattern does not protect from having none * or both variables set by programming errors. Instead, a single instance of Either can be used, which guarantees * exactly one type will be set. * </p> * * @param <S> first possible type for the value. * @param <T> second possible type for the value. */ @AllArgsConstructor(access = AccessLevel.PRIVATE) public abstract class Either<S, T> { protected final Optional<S> s; protected final Optional<T> t; /** * An instance of {@link Either} with value of type {@link S}. */ public static class Left<S, T> extends Either<S, T> { public Left(S s) { super(Optional.fromNullable(s), Optional.<T>absent()); } /** * @return value of type {@link S}. */ public S getLeft() { return this.s.orNull(); } } /** * An instance of {@link Either} with value of type {@link T}. */ public static class Right<S, T> extends Either<S, T> { public Right(T t) { super(Optional.<S>absent(), Optional.fromNullable(t)); } /** * @return value of type {@link T}. */ public T getRight() { return this.t.orNull(); } } /** * Create an instance of {@link Either} with value of type {@link S}. * @param left value of this instance. * @return an instance of {@link Left}. */ public static <S, T> Either<S, T> left(S left) { return new Left<>(left); } /** * Create an instance of {@link Either} with value of type {@link T}. * @param right value of this instance. * @return an instance of {@link Right}. */ public static <S, T> Either<S, T> right(T right) { return new Right<>(right); } /** * Get the value of this {@link Either} instance, returned as class {@link Object}. To get a strongly typed return, * check the specific type of {@link Either} and call {@link Left#getLeft} or {@link Right#getRight}. * @return value as an instance of {@link Object}. */ public Object get() { if (this instanceof Left) { return this.s.orNull(); } return this.t.orNull(); } }