package com.neoteric.starter.jackson.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import java.util.List;
import java.util.Map;
import java.util.Objects;

@JsonDeserialize(builder = JsonApiList.JsonApiListBuilder.class)
public class JsonApiList<T> {

    public static final String DATA_JSON = "data";
    public static final String META_JSON = "meta";
    public static final String META_TOTAL_JSON = "total";

    @JsonProperty(DATA_JSON)
    private final List<T> data;

    @JsonProperty(META_JSON)
    private final Map<String, Object> meta;

    private final int hashCodeValue;

    @JsonCreator
    public JsonApiList(@JsonProperty(DATA_JSON) List<T> data, @JsonProperty(META_JSON) Map<String, Object> meta) {
        this.data = data == null ? ImmutableList.of() : ImmutableList.copyOf(data);
        this.meta = meta == null ? ImmutableMap.of() : ImmutableMap.copyOf(meta);
        this.hashCodeValue = Objects.hash(data, meta);
    }

    public List<T> getData() {
        return data;
    }

    public Map<String, Object> getMeta() {
        return meta;
    }

    @JsonIgnore
    public int getTotal() {
        return meta.containsKey(META_TOTAL_JSON) ? (int) meta.get(META_TOTAL_JSON) : 0;
    }

    @Override
    public int hashCode() {
        return hashCodeValue;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .omitNullValues()
                .add("data", data)
                .add("meta", meta)
                .toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        } else if (obj instanceof JsonApiList) {
            JsonApiList<?> other = (JsonApiList<?>) obj;
            return Objects.equals(this.meta, other.meta) &&
                    Objects.deepEquals(this.data, other.data);
        } else {
            return false;
        }
    }

    public static <T> JsonApiListBuilder<T> wrap(T singleElementData) {
        return wrap(Lists.newArrayList(singleElementData));
    }

    public static <T> JsonApiListBuilder<T> wrap(List<T> data) {
        return new JsonApiListBuilder<T>(data);
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    @JsonPOJOBuilder(withPrefix = "")
    public static class JsonApiListBuilder<T> {

        private List<T> data;
        private Map<String, Object> meta;

        public JsonApiListBuilder() {
        }

        public JsonApiListBuilder(List<T> data) {
            this.data = data;
        }

        public JsonApiListBuilder<T> meta(Map<String, Object> meta) {
            this.meta = meta;
            return this;
        }

        public JsonApiListBuilder<T> meta(String field, Object value) {
            if (meta == null) {
                meta = Maps.newHashMap();
            }
            meta.put(field, value);
            return this;
        }

        public JsonApiListBuilder<T> total(int total) {
            if (meta == null) {
                meta = Maps.newHashMap();
            }
            meta.put(JsonApiList.META_TOTAL_JSON, total);
            return this;
        }

        public JsonApiList<T> build() {
            return new JsonApiList<T>(data, meta);
        }
    }
}
@@ -191,210 +191,16 @@
 Json
-IgnoreProperties;%0Aimport com.fasterxml.jackson.annotation.JsonProperty;%0Aimport com.fasterxml.jackson.databind.annotation.JsonDeserialize;%0Aimport com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder
+Property
 ;%0Aim
@@ -491,73 +491,8 @@
 s;%0A%0A
-@JsonDeserialize(builder = JsonApiList.JsonApiListBuilder.class)%0A
 publ
@@ -2452,94 +2452,8 @@
  %7D%0A%0A
-    @JsonIgnoreProperties(ignoreUnknown = true)%0A    @JsonPOJOBuilder(withPrefix = %22%22)%0A
     
@@ -2492,25 +2492,24 @@
 uilder%3CT%3E %7B%0A
-%0A
         priv

Use JsonCreator instead of builder due to the unresolved bug: https://github.com/FasterXML/jackson-databind/issues/921