package sk.stuba.fiit.perconik.utilities.reflect.accessor; import java.util.List; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import sk.stuba.fiit.perconik.utilities.MoreThrowables; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagateIfInstanceOf; import static com.google.common.collect.Lists.newArrayListWithExpectedSize; import static com.google.common.collect.Lists.newLinkedList; abstract class AbstractLookup<T> implements Lookup<T> { final List<Accessor<? extends T>> accessors; final Optional<RuntimeException> suppression; AbstractLookup(AbstractBuilder<T> builder) { this.accessors = ImmutableList.copyOf(builder.accessors); if (!builder.suppressions.isEmpty()) { RuntimeException suppressor = new AccessorConstructionException("Accessor construction failed"); this.suppression = Optional.of(MoreThrowables.initializeSuppressor(suppressor, Lists.reverse(builder.suppressions))); } else { this.suppression = Optional.absent(); } } static abstract class AbstractBuilder<T> { final List<Accessor<? extends T>> accessors; final List<Throwable> suppressions; public AbstractBuilder() { this.accessors = newArrayListWithExpectedSize(8); this.suppressions = newArrayListWithExpectedSize(8); } final void add(Accessor<? extends T> accessor) { this.accessors.add(checkNotNull(accessor)); } final void handle(Throwable e) { propagateIfInstanceOf(e, NullPointerException.class); this.suppressions.add(e); } public abstract AbstractLookup<T> build(); } public final T get() { List<Throwable> suppressions = newLinkedList(); for (Accessor<? extends T> accessor: this.accessors) { try { return accessor.get(); } catch (Throwable e) { if (e.getClass() == AccessorInvocationException.class) { e = e.getCause(); } suppressions.add(e); } } RuntimeException failure = new AccessorInvocationException("Accessor invocation failed"); suppressions = Lists.reverse(suppressions); if (this.suppression.isPresent()) { suppressions.add(this.suppression.get()); } throw MoreThrowables.initializeSuppressor(failure, suppressions); } }