/* * Copyright (C) 2014 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.cloud.genomics.dataflow.coders; import com.google.api.client.googleapis.util.Utils; import com.google.api.client.json.GenericJson; import com.google.api.client.json.JsonFactory; import com.google.cloud.dataflow.sdk.coders.CannotProvideCoderException; import com.google.cloud.dataflow.sdk.coders.Coder; import com.google.cloud.dataflow.sdk.coders.CoderProvider; import com.google.cloud.dataflow.sdk.coders.SerializableCoder; import com.google.cloud.dataflow.sdk.coders.StringUtf8Coder; import com.google.cloud.dataflow.sdk.coders.protobuf.ProtoCoder; import com.google.cloud.dataflow.sdk.util.CloudObject; import com.google.cloud.dataflow.sdk.values.TypeDescriptor; import com.google.protobuf.Message; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import java.io.IOException; import java.io.Serializable; /** * Can be used as a coder for any object that extends GenericJson. * This includes all objects in the Google Genomics Java client library. */ public class GenericJsonCoder<T extends GenericJson> extends DelegatingAtomicCoder<T, String> { private static final JsonFactory JSON_FACTORY = Utils.getDefaultJsonFactory(); private static final Coder<String> STRING_CODER = StringUtf8Coder.of(); public static <T extends GenericJson> GenericJsonCoder<T> of(Class<T> type) { return new GenericJsonCoder<>(type); } @JsonCreator @SuppressWarnings("unchecked") public static <T extends GenericJson> GenericJsonCoder<T> of(@JsonProperty("type") String type) throws ClassNotFoundException { return of((Class<T>) Class.forName(type)); } private final Class<T> type; private GenericJsonCoder(Class<T> type) { super(STRING_CODER); this.type = type; } @Override public CloudObject asCloudObject() { CloudObject result = super.asCloudObject(); result.put("type", type.getName()); return result; } @Override protected T from(String object) throws IOException { return JSON_FACTORY.fromString(object, type); } @Override protected String to(T object) throws IOException { return JSON_FACTORY.toString(object); } /** * Coder provider for all objects in the Google Genomics Java client library. */ public static final CoderProvider PROVIDER = new CoderProvider() { @Override @SuppressWarnings("unchecked") public <T> Coder<T> getCoder(TypeDescriptor<T> typeDescriptor) throws CannotProvideCoderException { Class<T> rawType = (Class<T>) typeDescriptor.getRawType(); if (!GenericJson.class.isAssignableFrom(rawType)) { if (Message.class.isAssignableFrom(rawType)) { return (Coder<T>) ProtoCoder.of((Class<? extends Message>) rawType); } else if (Serializable.class.isAssignableFrom(rawType)) { // Fall back this here because if this is used as the fallback coder, it overwrites the // default fallback CoderProvider of SerializableCoder.PROVIDER. return (Coder<T>) SerializableCoder.of((Class<? extends Serializable>) rawType); } else { throw new CannotProvideCoderException("Class " + rawType + " does not implement GenericJson, Message, or Serializable"); } } return (Coder<T>) GenericJsonCoder.of((Class<? extends GenericJson>) rawType); } }; }