/* * Copyright (c) 2015, Jurriaan Mous and contributors as indicated by the @author tags. * * 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 mousio.etcd4j.responses; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.module.afterburner.AfterburnerModule; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; import io.netty.handler.codec.http.HttpHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.DataInput; import java.io.IOException; import java.nio.charset.Charset; /** * @author Luca Burgazzoli */ public class EtcdResponseDecoders { private static final Logger LOGGER = LoggerFactory.getLogger(EtcdResponseDecoders.class); protected static final CharSequence X_ETCD_CLUSTER_ID = "X-Etcd-Cluster-Id"; protected static final CharSequence X_ETCD_INDEX = "X-Etcd-Index"; protected static final CharSequence X_RAFT_INDEX = "X-Raft-Index"; protected static final CharSequence X_RAFT_TERM = "X-Raft-Term"; public static final EtcdResponseDecoder<String> STRING_DECODER = new StringDecoder(); private static final ObjectMapper MAPPER = new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .registerModules(new AfterburnerModule()); public static class JsonDecoder<T> implements EtcdResponseDecoder<T> { private final Class<T> type; public JsonDecoder(Class<T> type) { this.type = type; } @Override public T decode(HttpHeaders headers, ByteBuf content) throws EtcdException, IOException { try { final DataInput di = new ByteBufInputStream(content); final T value = MAPPER.readValue(di, this.type); if (headers != null && EtcdHeaderAwareResponse.class.isAssignableFrom(this.type)) { ((EtcdHeaderAwareResponse) value).loadHeaders(headers); } return value; } catch (NoSuchMethodError e) { LOGGER.warn("Jackson failed to deserialize JSON, please check you have Jackson > 2.8.0 in your classpath", e); throw new RuntimeException(e); } } } public static class StringDecoder implements EtcdResponseDecoder<String> { @Override public String decode(HttpHeaders headers, ByteBuf content) throws EtcdException, IOException { return content.toString(Charset.defaultCharset()); } } public abstract static class StringToObjectDecoder<T> implements EtcdResponseDecoder<T> { @Override public T decode(HttpHeaders headers, ByteBuf content) throws EtcdException, IOException { return newInstance(content.toString(Charset.defaultCharset())); } protected abstract T newInstance(String message); } // *************************************************************************** // // *************************************************************************** public static <T> EtcdResponseDecoder<T> json(Class<T> type) { return new JsonDecoder<>(type); } public static EtcdResponseDecoder<String> string() { return new StringDecoder(); } }