Our falling back to string representation is actively hurtful, as we end
up admitting the wrong type. We really should be treating union as a
complex type and not handle it at all, but that may break users more
than we want to in one release.
JIRA: YANGTOOLS-1427
Change-Id: I944e5869a718a768799bf334e4291cd0eb861e98
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
private final ImmutableSet<String> validBits;
@SuppressWarnings("unchecked")
private final ImmutableSet<String> validBits;
@SuppressWarnings("unchecked")
- private BitsStringCodec(final @NonNull BitsTypeDefinition typeDef) {
- super(typeDef, (Class<Set<String>>) (Class<?>) Set.class);
+ private BitsStringCodec(final BitsTypeDefinition typeDef) {
+ super(requireNonNull(typeDef), (Class<Set<String>>) (Class<?>) Set.class);
validBits = ImmutableSet.copyOf(Collections2.transform(typeDef.getBits(), Bit::getName));
}
public static BitsStringCodec from(final BitsTypeDefinition type) {
validBits = ImmutableSet.copyOf(Collections2.transform(typeDef.getBits(), Bit::getName));
}
public static BitsStringCodec from(final BitsTypeDefinition type) {
- return new BitsStringCodec(requireNonNull(type));
+ return new BitsStringCodec(type);
@Beta
public final class BooleanStringCodec extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
implements BooleanCodec<String> {
@Beta
public final class BooleanStringCodec extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
implements BooleanCodec<String> {
- private BooleanStringCodec(final @NonNull BooleanTypeDefinition typeDef) {
- super(typeDef, Boolean.class);
+ private BooleanStringCodec(final BooleanTypeDefinition typeDef) {
+ super(requireNonNull(typeDef), Boolean.class);
- public static @NonNull BooleanStringCodec from(final BooleanTypeDefinition normalizedType) {
- return new BooleanStringCodec(requireNonNull(normalizedType));
+ public static @NonNull BooleanStringCodec from(final BooleanTypeDefinition typeDef) {
+ return new BooleanStringCodec(typeDef);
public final class DecimalStringCodec extends TypeDefinitionAwareCodec<Decimal64, DecimalTypeDefinition>
implements DecimalCodec<String> {
private DecimalStringCodec(final DecimalTypeDefinition typeDef) {
public final class DecimalStringCodec extends TypeDefinitionAwareCodec<Decimal64, DecimalTypeDefinition>
implements DecimalCodec<String> {
private DecimalStringCodec(final DecimalTypeDefinition typeDef) {
- super(typeDef, Decimal64.class);
+ super(requireNonNull(typeDef), Decimal64.class);
}
public static @NonNull DecimalStringCodec from(final DecimalTypeDefinition type) {
}
public static @NonNull DecimalStringCodec from(final DecimalTypeDefinition type) {
- return new DecimalStringCodec(requireNonNull(type));
+ return new DecimalStringCodec(type);
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkArgument;
-import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.common.Empty;
import org.opendaylight.yangtools.yang.data.api.codec.EmptyCodec;
import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
import org.opendaylight.yangtools.yang.common.Empty;
import org.opendaylight.yangtools.yang.data.api.codec.EmptyCodec;
import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
- protected @NonNull String serializeImpl(final Empty input) {
+ protected String serializeImpl(final Empty input) {
return "";
}
}
\ No newline at end of file
return "";
}
}
\ No newline at end of file
import com.google.common.annotations.Beta;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import com.google.common.annotations.Beta;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
-import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.data.api.codec.EnumCodec;
import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
import org.opendaylight.yangtools.yang.data.api.codec.EnumCodec;
import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
implements EnumCodec<String> {
private final ImmutableMap<String, String> values;
implements EnumCodec<String> {
private final ImmutableMap<String, String> values;
- private EnumStringCodec(final @NonNull EnumTypeDefinition typeDef) {
- super(typeDef, String.class);
+ private EnumStringCodec(final EnumTypeDefinition typeDef) {
+ super(requireNonNull(typeDef), String.class);
values = typeDef.getValues().stream()
// Intern the String to get wide reuse
.map(pair -> pair.getName().intern())
.collect(ImmutableMap.toImmutableMap(Functions.identity(), Functions.identity()));
}
values = typeDef.getValues().stream()
// Intern the String to get wide reuse
.map(pair -> pair.getName().intern())
.collect(ImmutableMap.toImmutableMap(Functions.identity(), Functions.identity()));
}
- public static EnumStringCodec from(final EnumTypeDefinition normalizedType) {
- return new EnumStringCodec(requireNonNull(normalizedType));
+ public static EnumStringCodec from(final EnumTypeDefinition typeDef) {
+ return new EnumStringCodec(typeDef);
import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.slf4j.LoggerFactory;
public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> extends AbstractDataStringCodec<J> {
public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> extends AbstractDataStringCodec<J> {
+ private static final boolean ENABLE_UNION_CODEC =
+ !Boolean.getBoolean("org.opendaylight.yangtools.yang.data.impl.codec.disable-union");
+
+ static {
+ if (!ENABLE_UNION_CODEC) {
+ LoggerFactory.getLogger(TypeDefinitionAwareCodec.class).info("Support for unions is disabled");
+ }
+ }
+
private final @NonNull Class<J> inputClass;
private final @Nullable T typeDefinition;
private final @NonNull Class<J> inputClass;
private final @Nullable T typeDefinition;
+ // FIXME: is this even useful?
public Optional<T> getTypeDefinition() {
return Optional.ofNullable(typeDefinition);
}
public Optional<T> getTypeDefinition() {
return Optional.ofNullable(typeDefinition);
}
return AbstractIntegerStringCodec.from((Int64TypeDefinition) typeDefinition);
} else if (typeDefinition instanceof StringTypeDefinition) {
return StringStringCodec.from((StringTypeDefinition)typeDefinition);
return AbstractIntegerStringCodec.from((Int64TypeDefinition) typeDefinition);
} else if (typeDefinition instanceof StringTypeDefinition) {
return StringStringCodec.from((StringTypeDefinition)typeDefinition);
- } else if (typeDefinition instanceof UnionTypeDefinition) {
- return UnionStringCodec.from((UnionTypeDefinition)typeDefinition);
} else if (typeDefinition instanceof Uint8TypeDefinition) {
return AbstractIntegerStringCodec.from((Uint8TypeDefinition) typeDefinition);
} else if (typeDefinition instanceof Uint16TypeDefinition) {
} else if (typeDefinition instanceof Uint8TypeDefinition) {
return AbstractIntegerStringCodec.from((Uint8TypeDefinition) typeDefinition);
} else if (typeDefinition instanceof Uint16TypeDefinition) {
return AbstractIntegerStringCodec.from((Uint32TypeDefinition) typeDefinition);
} else if (typeDefinition instanceof Uint64TypeDefinition) {
return AbstractIntegerStringCodec.from((Uint64TypeDefinition) typeDefinition);
return AbstractIntegerStringCodec.from((Uint32TypeDefinition) typeDefinition);
} else if (typeDefinition instanceof Uint64TypeDefinition) {
return AbstractIntegerStringCodec.from((Uint64TypeDefinition) typeDefinition);
+ } else if (ENABLE_UNION_CODEC && typeDefinition instanceof UnionTypeDefinition) {
+ return UnionStringCodec.from((UnionTypeDefinition)typeDefinition);
import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNull;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.yang.data.api.codec.UnionCodec;
import org.opendaylight.yangtools.yang.data.api.codec.UnionCodec;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
implements UnionCodec<String> {
private static final Logger LOG = LoggerFactory.getLogger(UnionStringCodec.class);
implements UnionCodec<String> {
private static final Logger LOG = LoggerFactory.getLogger(UnionStringCodec.class);
- UnionStringCodec(final UnionTypeDefinition typeDef) {
+ private final ImmutableList<TypeDefinitionAwareCodec<Object, ?>> codecs;
+
+ private UnionStringCodec(final UnionTypeDefinition typeDef,
+ final ImmutableList<TypeDefinitionAwareCodec<Object, ?>> codecs) {
super(requireNonNull(typeDef), Object.class);
super(requireNonNull(typeDef), Object.class);
+ this.codecs = requireNonNull(codecs);
- static TypeDefinitionAwareCodec<?, UnionTypeDefinition> from(final UnionTypeDefinition normalizedType) {
- return new UnionStringCodec(normalizedType);
+ static @Nullable TypeDefinitionAwareCodec<?, UnionTypeDefinition> from(final UnionTypeDefinition typeDef) {
+ final var types = typeDef.getTypes();
+ final var builder = ImmutableList.<TypeDefinitionAwareCodec<Object, ?>>builderWithExpectedSize(types.size());
+ for (var type : types) {
+ final var codec = from(type);
+ if (codec == null) {
+ LOG.debug("Cannot handle {} because of unhandled component {}", typeDef, type);
+ return null;
+ }
+ builder.add(codec);
+ }
+ return new UnionStringCodec(typeDef, builder.build());
- @SuppressWarnings("checkstyle:illegalCatch")
protected Object deserializeImpl(final String stringRepresentation) {
protected Object deserializeImpl(final String stringRepresentation) {
- for (final TypeDefinition<?> type : getTypeDefinition().get().getTypes()) {
- final TypeDefinitionAwareCodec<Object, ?> typeAwareCodec = from(type);
- if (typeAwareCodec == null) {
- /*
- * This is a type for which we have no codec (eg identity ref) so we'll say it's
- * valid
- */
- return stringRepresentation;
- }
-
+ List<IllegalArgumentException> suppressed = null;
+ for (var codec : codecs) {
- return typeAwareCodec.deserialize(stringRepresentation);
- } catch (final Exception e) {
- LOG.debug("Value {} did not matched representation for {}",stringRepresentation,type,e);
+ return codec.deserialize(stringRepresentation);
+ } catch (final IllegalArgumentException e) {
// invalid - try the next union type.
// invalid - try the next union type.
+ LOG.debug("Value {} did not match codec {}", stringRepresentation, codec, e);
+ if (suppressed == null) {
+ suppressed = new ArrayList<>();
+ }
+ suppressed.add(e);
- throw new IllegalArgumentException("Invalid value \"" + stringRepresentation + "\" for union type.");
+ final var ex = new IllegalArgumentException("Invalid value \"" + stringRepresentation + "\" for union type.");
+ if (suppressed != null) {
+ suppressed.forEach(ex::addSuppressed);
+ }
+ throw ex;