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 static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.collect.ImmutableList;
14 import com.google.gson.stream.JsonWriter;
15 import java.io.IOException;
16 import java.util.Iterator;
17 import java.util.List;
18 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
23 * Union codec based with a pre-calculated set of sub-types.
25 * @author Robert Varga
27 * @param <T> Data representation type
29 abstract class UnionJSONCodec<T> implements JSONCodec<T> {
30 private static final class Diverse extends UnionJSONCodec<Object> {
31 Diverse(final List<JSONCodec<?>> codecs) {
36 public Class<Object> getDataType() {
41 private static final class SingleType<T> extends UnionJSONCodec<T> {
42 private final Class<T> dataClass;
44 SingleType(final Class<T> dataClass, final List<JSONCodec<?>> codecs) {
46 this.dataClass = requireNonNull(dataClass);
50 public Class<T> getDataType() {
55 private static final Logger LOG = LoggerFactory.getLogger(UnionJSONCodec.class);
57 private final ImmutableList<JSONCodec<?>> codecs;
59 UnionJSONCodec(final List<JSONCodec<?>> codecs) {
60 this.codecs = ImmutableList.copyOf(codecs);
63 static UnionJSONCodec<?> create(final UnionTypeDefinition type, final List<JSONCodec<?>> codecs) {
64 final Iterator<JSONCodec<?>> it = codecs.iterator();
65 verify(it.hasNext(), "Union %s has no subtypes", type);
67 Class<?> dataClass = it.next().getDataType();
68 while (it.hasNext()) {
69 final Class<?> next = it.next().getDataType();
70 if (!dataClass.equals(next)) {
71 LOG.debug("Type {} has diverse data classes: {} and {}", type, dataClass, next);
72 return new Diverse(codecs);
76 LOG.debug("Type {} has single data class {}", type, dataClass);
77 return new SingleType<>(dataClass, codecs);
81 @SuppressWarnings("checkstyle:illegalCatch")
82 public final T parseValue(final Object ctx, final String str) {
83 for (JSONCodec<?> codec : codecs) {
86 ret = codec.parseValue(ctx, str);
87 } catch (RuntimeException e) {
88 LOG.debug("Codec {} did not accept input '{}'", codec, str, e);
92 return getDataType().cast(ret);
95 throw new IllegalArgumentException("Invalid value \"" + str + "\" for union type.");
99 @SuppressWarnings("checkstyle:illegalCatch")
100 public final void writeValue(final JsonWriter ctx, final T value) throws IOException {
101 for (JSONCodec<?> codec : codecs) {
102 if (!codec.getDataType().isInstance(value)) {
103 LOG.debug("Codec {} cannot accept input {}, skipping it", codec, value);
107 @SuppressWarnings("unchecked")
108 final JSONCodec<Object> objCodec = (JSONCodec<Object>) codec;
110 objCodec.writeValue(ctx, value);
112 } catch (RuntimeException e) {
113 LOG.debug("Codec {} failed to serialize {}", codec, value, e);
117 throw new IllegalArgumentException("No codecs could serialize" + value);