001package io.ebean.test;
002
003import com.fasterxml.jackson.annotation.JsonInclude;
004import com.fasterxml.jackson.databind.DeserializationFeature;
005import com.fasterxml.jackson.databind.JsonNode;
006import com.fasterxml.jackson.databind.ObjectMapper;
007import com.fasterxml.jackson.databind.SerializationFeature;
008import com.fasterxml.jackson.databind.type.CollectionType;
009import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
010
011import java.io.IOException;
012import java.util.List;
013
014/**
015 * Helper to convert to and from json using Jackson object mapper and
016 * perform some useful asserts based on json content.
017 */
018public class Json {
019
020  /**
021   * For reading resource json content into a bean, list or jsonNode in a fluid style.
022   */
023  public static class Resource {
024    private final String resourcePath;
025
026    private Resource(String resourcePath) {
027      this.resourcePath = resourcePath;
028    }
029
030    /**
031     * Return as a plain bean.
032     */
033    <T> T asBean(Class<T> cls) {
034      return Json.read(cls, readResource(resourcePath));
035    }
036
037    /**
038     * Return as a list of beans.
039     */
040    <T> List<T> asList(Class<T> cls) {
041      return Json.readList(cls, readResource(resourcePath));
042    }
043
044    /**
045     * Return as a JsonNode.
046     */
047    JsonNode asNode() {
048      return Json.readNodeFromResource(resourcePath);
049    }
050  }
051
052  private static final ObjectMapper MAPPER = initMapper();
053
054  /**
055   * For fluid style reading resource json content and return as a
056   * bean, list of bean or JsonNode.
057   * <pre>{@code
058   *
059   *   PlainBean bean =
060   *     Json.resource("/example/plain-list.json").asBean(PlainBean.class);
061   *
062   *   List<PlainBean> list =
063   *     Json.resource("/example/plain-list.json").asList(PlainBean.class);
064   *
065   *   JsonNode jsonNode =
066   *     Json.resource("/example/plain-list.json").asJsonNode();
067   *
068   * }</pre>
069   *
070   * @param resourcePath The resource path where the json content is read from
071   * @return The resource to convert to a bean or jsonNode etc
072   */
073  public static Resource resource(String resourcePath) {
074    return new Resource(resourcePath);
075  }
076
077  /**
078   * Assert all the fields in the expectedJson are present in actualJson and values match.
079   */
080  public static void assertContains(String actualJson, String expectedJson) {
081    assertContains(readNode(actualJson), readNode(expectedJson));
082  }
083
084  /**
085   * Assert all the fields in the expectedJson are present in actualJson and values match.
086   */
087  public static void assertContains(JsonNode actualJsonNode, JsonNode expectedJsonNode) {
088    JsonAssertContains.assertContains(actualJsonNode, expectedJsonNode);
089  }
090
091  /**
092   * Read the content for the given resource path.
093   */
094  public static String readResource(String resourcePath) {
095    return IOUtils.readResource(resourcePath);
096  }
097
098  /**
099   * Return a bean from json content of a resource path.
100   */
101  public static <T> T readFromResource(Class<T> type, String resourcePath) {
102    return read(type, readResource(resourcePath));
103  }
104
105  /**
106   * Return a typed object from json content.
107   */
108  public static <T> T read(Class<T> type, String json) {
109    try {
110      return MAPPER.readValue(json, type);
111    } catch (IOException e) {
112      throw new RuntimeException(e);
113    }
114  }
115
116  /**
117   * Return a list of a given type from json content.
118   */
119  public static <T> List<T> readList(Class<T> type, String json) {
120    final CollectionType collectionType = MAPPER.getTypeFactory().constructCollectionType(List.class, type);
121    try {
122      return MAPPER.readValue(json, collectionType);
123    } catch (IOException e) {
124      throw new RuntimeException(e);
125    }
126  }
127
128  /**
129   * Parse json into a generic JsonNode structure from resource.
130   */
131  public static JsonNode readNodeFromResource(String resourcePath) {
132    return readNode(IOUtils.readResource(resourcePath));
133  }
134
135  /**
136   * Parse json into a generic JsonNode structure.
137   */
138  public static JsonNode readNode(String json) {
139    try {
140      return MAPPER.readTree(json);
141    } catch (IOException e) {
142      throw new RuntimeException(e);
143    }
144  }
145
146  /**
147   * Serialize object to string
148   */
149  public static String toJsonString(Object bean) {
150    try {
151      return MAPPER.writeValueAsString(bean);
152    } catch (IOException e) {
153      throw new RuntimeException(e);
154    }
155  }
156
157  private static ObjectMapper initMapper() {
158    return new ObjectMapper()
159      .registerModule(new JavaTimeModule())
160      .configure(SerializationFeature.INDENT_OUTPUT, true)
161      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
162      .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
163      .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
164      .configure(SerializationFeature.INDENT_OUTPUT, true)
165      .setSerializationInclusion(JsonInclude.Include.NON_NULL);
166  }
167
168}