2 * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.codec.gson;
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Verify;
12 import com.google.common.collect.ImmutableList;
13 import com.google.gson.stream.JsonWriter;
14 import java.io.IOException;
15 import java.util.Iterator;
16 import java.util.List;
17 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
22 * Union codec based with a pre-calculated set of sub-types.
24 * @author Robert Varga
26 * @param <T> Data representation type
28 abstract class UnionJSONCodec<T> implements JSONCodec<T> {
29 private static final class Diverse extends UnionJSONCodec<Object> {
30 Diverse(final List<JSONCodec<?>> codecs) {
35 public Class<Object> getDataType() {
40 private static final class SingleType<T> extends UnionJSONCodec<T> {
41 private final Class<T> dataClass;
43 SingleType(final Class<T> dataClass, final List<JSONCodec<?>> codecs) {
45 this.dataClass = Preconditions.checkNotNull(dataClass);
49 public Class<T> getDataType() {
54 private static final Logger LOG = LoggerFactory.getLogger(UnionJSONCodec.class);
56 private final List<JSONCodec<?>> codecs;
58 UnionJSONCodec(final List<JSONCodec<?>> codecs) {
59 this.codecs = ImmutableList.copyOf(codecs);
62 static UnionJSONCodec<?> create(final UnionTypeDefinition type, final List<JSONCodec<?>> codecs) {
63 final Iterator<JSONCodec<?>> it = codecs.iterator();
64 Verify.verify(it.hasNext(), "Union %s has no subtypes", type);
66 Class<?> dataClass = it.next().getDataType();
67 while (it.hasNext()) {
68 final Class<?> next = it.next().getDataType();
69 if (!dataClass.equals(next)) {
70 LOG.debug("Type {} has diverse data classes: {} and {}", type, dataClass, next);
71 return new Diverse(codecs);
75 LOG.debug("Type {} has single data class {}", type, dataClass);
76 return new SingleType<>(dataClass, codecs);
80 @SuppressWarnings("checkstyle:illegalCatch")
81 public final T parseValue(final Object ctx, final String str) {
82 for (JSONCodec<?> codec : codecs) {
85 ret = codec.parseValue(ctx, str);
86 } catch (RuntimeException e) {
87 LOG.debug("Codec {} did not accept input '{}'", codec, str, e);
91 return getDataType().cast(ret);
94 throw new IllegalArgumentException("Invalid value \"" + str + "\" for union type.");
98 @SuppressWarnings("checkstyle:illegalCatch")
99 public final void writeValue(final JsonWriter ctx, final T value) throws IOException {
100 for (JSONCodec<?> codec : codecs) {
101 if (!codec.getDataType().isInstance(value)) {
102 LOG.debug("Codec {} cannot accept input {}, skipping it", codec, value);
106 @SuppressWarnings("unchecked")
107 final JSONCodec<Object> objCodec = (JSONCodec<Object>) codec;
109 objCodec.writeValue(ctx, value);
111 } catch (RuntimeException e) {
112 LOG.debug("Codec {} failed to serialize {}", codec, value, e);
116 throw new IllegalArgumentException("No codecs could serialize" + value);