View Javadoc
1   /**
2    * Copyright (c) 2013-2023, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.github;
31  
32  import com.jcabi.aspects.Immutable;
33  import com.jcabi.aspects.Loggable;
34  import java.io.IOException;
35  import javax.json.JsonNumber;
36  import javax.json.JsonObject;
37  import javax.json.JsonString;
38  import javax.json.JsonValue;
39  import javax.json.JsonValue.ValueType;
40  import lombok.EqualsAndHashCode;
41  import lombok.ToString;
42  
43  /**
44   * Smart JSON (supplementary help class).
45   *
46   * @author Yegor Bugayenko (yegor256@gmail.com)
47   * @version $Id: c3f13a2237132fd965d19d2c920df7a5d8a103d1 $
48   * @since 0.5
49   */
50  @Immutable
51  @ToString
52  @Loggable(Loggable.DEBUG)
53  @EqualsAndHashCode(of = "object")
54  @SuppressWarnings("PMD.AvoidDuplicateLiterals")
55  final class SmartJson {
56  
57      /**
58       * Encapsulated JSON object.
59       */
60      private final transient JsonReadable object;
61  
62      /**
63       * Public ctor.
64       * @param obj Readable object
65       */
66      SmartJson(final JsonReadable obj) {
67          this.object = obj;
68      }
69  
70      /**
71       * Get its property as string.
72       * @param name Name of the property
73       * @return Value
74       * @throws IOException If there is any I/O problem
75       */
76      public String text(
77          final String name
78      ) throws IOException {
79          return this.value(name, JsonString.class).getString();
80      }
81  
82      /**
83       * Get its property as number.
84       * @param name Name of the property
85       * @return Value
86       * @throws IOException If there is any I/O problem
87       */
88      public int number(
89          final String name
90      ) throws IOException {
91          return this.value(name, JsonNumber.class).intValue();
92      }
93  
94      /**
95       * Get JSON.
96       * @return JSON
97       * @throws IOException If there is any I/O problem
98       * @since 0.14
99       */
100     public JsonObject json() throws IOException {
101         return this.object.json();
102     }
103 
104     /**
105      * Get its property as custom type.
106      * @param name Name of the property
107      * @param type Type of result expected
108      * @return Value
109      * @throws IOException If there is any I/O problem
110      * @param <T> Type expected
111      */
112     public <T> T value(
113         final String name,
114         final Class<T> type
115     ) throws IOException {
116         final JsonObject json = this.json();
117         if (!json.containsKey(name)) {
118             throw new IllegalStateException(
119                 String.format(
120                     "'%s' is absent in JSON: %s", name, json
121                 )
122             );
123         }
124         final JsonValue value = json.get(name);
125         if (value == null) {
126             throw new IllegalStateException(
127                 String.format(
128                     "'%s' is NULL in %s", name, json
129                 )
130             );
131         }
132         if (value.getClass().isAssignableFrom(type)) {
133             throw new IllegalStateException(
134                 String.format(
135                     "'%s' is not of type %s", name, type
136                 )
137             );
138         }
139         return type.cast(value);
140     }
141 
142     /**
143      * Checks if a certain key is present
144      *  AND its ValueType isn't ValueType.NULL.
145      * @param name Name of the key which ValueType should be checked.
146      * @return Returns <code>true</code> if key <code>name</code> is present
147      *  and its ValueType isn't ValueType.NULL, <code>false</code> otherwise.
148      * @throws IOException If there is any I/O problem
149      */
150     public boolean hasNotNull(
151         final String name
152     ) throws IOException {
153         final JsonValue value = this.object.json().get(name);
154         return value != null
155             && !ValueType.NULL.equals(value.getValueType());
156     }
157 }