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 }