import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
+import com.google.common.util.concurrent.ExecutionError;
+import com.google.common.util.concurrent.UncheckedExecutionException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
+import javax.annotation.Nullable;
import org.opendaylight.yangtools.concepts.Codec;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
final class UnionTypeCodec extends ReflectionBasedCodec {
+ private final Codec<Object, Object> identityrefCodec;
private final ImmutableSet<UnionValueOptionContext> typeCodecs;
private final Constructor<?> charConstructor;
- private UnionTypeCodec(final Class<?> unionCls,final Set<UnionValueOptionContext> codecs) {
+ private UnionTypeCodec(final Class<?> unionCls,final Set<UnionValueOptionContext> codecs,
+ @Nullable Codec<Object, Object> identityrefCodec) {
super(unionCls);
+ this.identityrefCodec = identityrefCodec;
try {
charConstructor = unionCls.getConstructor(char[].class);
typeCodecs = ImmutableSet.copyOf(codecs);
}
}
- static Callable<UnionTypeCodec> loader(final Class<?> unionCls, final UnionTypeDefinition unionType) {
+ static Callable<UnionTypeCodec> loader(final Class<?> unionCls, final UnionTypeDefinition unionType,
+ BindingCodecContext bindingCodecContext) {
return new Callable<UnionTypeCodec>() {
@Override
public UnionTypeCodec call() throws NoSuchMethodException, SecurityException {
+ Codec<Object, Object> identityrefCodec = null;
Set<UnionValueOptionContext> values = new HashSet<>();
- for(TypeDefinition<?> subtype : unionType.getTypes()) {
+ for (TypeDefinition<?> subtype : unionType.getTypes()) {
String methodName = "get" + BindingMapping.getClassName(subtype.getQName());
Method valueGetter = unionCls.getMethod(methodName);
Class<?> valueType = valueGetter.getReturnType();
- Codec<Object, Object> valueCodec = UnionTypeCodec.getCodecForType(valueType, subtype);
+ Codec<Object, Object> valueCodec = bindingCodecContext.getCodec(valueType, subtype);
+ if (Class.class.equals(valueType)) {
+ identityrefCodec = valueCodec;
+ }
values.add(new UnionValueOptionContext(valueType,valueGetter, valueCodec));
}
- return new UnionTypeCodec(unionCls, values);
+ return new UnionTypeCodec(unionCls, values, identityrefCodec);
}
};
}
- private static Codec<Object, Object> getCodecForType(final Class<?> valueType, final TypeDefinition<?> subtype) {
- if (subtype.getBaseType() instanceof UnionTypeDefinition) {
+ @Override
+ public Object deserialize(final Object input) {
+ if (identityrefCodec != null) {
try {
- return UnionTypeCodec.loader(valueType, (UnionTypeDefinition) subtype.getBaseType()).call();
- } catch (final Exception e) {
- throw new IllegalStateException("Could not construct Union Type Codec");
+ Object identityref = identityrefCodec.deserialize(input);
+ return typeClass.getConstructor(Class.class).newInstance(identityref);
+ } catch (UncheckedExecutionException | ExecutionError e) {
+ // ignore this exception caused by deserialize()
+ } catch (NoSuchMethodException e) {
+ // caused by getContructor(). this case shouldn't happen.
+ throw new IllegalStateException("Could not construct instance", e);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ // ignore this exception caused by newInstance()
}
- } else {
- return ValueTypeCodec.getCodecFor(valueType, subtype);
}
- }
-
- @Override
- public Object deserialize(final Object input) {
try {
if (input instanceof byte[]) {
return charConstructor.newInstance(BaseEncoding.base64().encode((byte[]) input).toCharArray());