ComputationTargetTypeMap { public void put(final ComputationTargetType key, final V value) { key.accept(new ComputationTargetTypeVisitor<Void, Void>() { @Override public Void visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final Void data) { for (ComputationTargetType type : types) { type.accept(this, data); } return null; } @Override public Void visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final Void data) { return types.get(types.size() - 1).accept(this, data); } @Override public Void visitNullComputationTargetType(final Void data) { final V nullValue = getNullValue(); if (nullValue == null) { if (replaceNullValue(null, value)) { return null; } else { throw new ConcurrentModificationException(); } } else { if (getFoldFunction() != null) { final V newValue = getFoldFunction().apply(nullValue, value); if (replaceNullValue(nullValue, newValue)) { return null; } else { throw new ConcurrentModificationException(); } } else { throw new IllegalStateException("Already held " + nullValue + " for NULL"); } } } @SuppressWarnings("unchecked") @Override public Void visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final Void data) { V newValue = (value != null) ? value : (V) NULL; final V previous = getUnderlying().putIfAbsent(type, newValue); if (previous == null) { return null; } else { if (previous == NULL) { if (getUnderlying().replace(type, previous, newValue)) { return null; } else { throw new ConcurrentModificationException(); } } if (getFoldFunction() != null) { newValue = getFoldFunction().apply(previous, value); if (newValue == null) { newValue = (V) NULL; } if (getUnderlying().replace(type, previous, newValue)) { return null; } else { throw new ConcurrentModificationException(); } } else { throw new IllegalStateException("Already held " + previous + " for " + key); } } } }, null); } ComputationTargetTypeMap();  ComputationTargetTypeMap(BinaryOperator<V> fold); BinaryOperator<V> getFoldFunction(); @SuppressWarnings("unchecked") V get(final ComputationTargetType key); V get(final Class<? extends UniqueIdentifiable> key); @SuppressWarnings("unchecked") V getDirect(final ComputationTargetType key); void put(final ComputationTargetType key, final V value); void put(final ComputationTargetType key, final V value, final BinaryOperator<V> replace); Iterable<V> values(); Iterable<Map.Entry<ComputationTargetType, V>> entries();  }
@Test(expectedExceptions = {IllegalStateException.class }) public void testCollision_direct() { final ComputationTargetTypeMap<String> map = new ComputationTargetTypeMap<String>(); map.put(ComputationTargetType.POSITION.or(ComputationTargetType.TRADE), "Pos|Trade"); map.put(ComputationTargetType.PORTFOLIO_NODE.containing(ComputationTargetType.POSITION), "Pos"); }