001/*
002 * Copyright 2020 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.api.jackson;
017
018import org.gbif.api.vocabulary.Rank;
019
020import java.io.IOException;
021import java.util.HashMap;
022import java.util.Map;
023
024import com.fasterxml.jackson.core.JsonGenerator;
025import com.fasterxml.jackson.core.JsonParser;
026import com.fasterxml.jackson.core.JsonToken;
027import com.fasterxml.jackson.databind.DeserializationContext;
028import com.fasterxml.jackson.databind.JsonDeserializer;
029import com.fasterxml.jackson.databind.JsonMappingException;
030import com.fasterxml.jackson.databind.JsonSerializer;
031import com.fasterxml.jackson.databind.SerializerProvider;
032
033/**
034 * Jackson {@link JsonSerializer} and Jackson {@link JsonDeserializer} classes for {@link Rank} that uses the common rank markers instead of enum names.
035 */
036public class RankSerde {
037
038  /**
039   * Jackson {@link JsonSerializer} for {@link Rank}.
040   */
041  public static class RankJsonSerializer extends JsonSerializer<Rank> {
042
043    @Override
044    public void serialize(Rank value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
045      if (value == null) {
046        jgen.writeNull();
047        return;
048      }
049      if (value.getMarker() == null) {
050        jgen.writeString(value.name().toLowerCase().replaceAll("_", " "));
051      } else {
052        jgen.writeString(value.getMarker());
053      }
054    }
055  }
056
057  /**
058   * Jackson {@link JsonDeserializer} for {@link Rank}.
059   */
060  public static class RankJsonDeserializer extends JsonDeserializer<Rank> {
061    private static final Map<String, Rank> RANKS = new HashMap<>();
062    static {
063      for (Rank r : Rank.values()) {
064        if (r.getMarker() != null) {
065          RANKS.put(r.getMarker(), r);
066        }
067      }
068    }
069
070    @Override
071    public Rank deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
072      if (jp.getCurrentToken() == JsonToken.VALUE_STRING) {
073        if (RANKS.containsKey(jp.getText())) {
074          return RANKS.get(jp.getText());
075
076        } else {
077          // try enum name as last resort
078          try {
079            return Rank.valueOf(jp.getText().toUpperCase().replace(" ", "_"));
080          } catch (IllegalArgumentException e) {
081            // swallow
082          }
083        }
084        return null;
085      }
086      throw JsonMappingException.from(jp, "Expected String");
087    }
088  }
089}