1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
package Torello.Java.JSON;

import javax.json.*;
import Torello.Java.StrPrint;

/**
 * The parent class of all Json Exceptions in this package.  This class contains several
 * convenience fields that will be auto-populated by any method inside Java HTML that would throw
 * this exception, or any of this exception's descendant classes.
 * 
 * <BR /><BR /><B>NOTE:</B> This class is abstract, and cannot be instantiated.
 * 
 * <EMBED CLASS=globalDefs DATA-STRUCT=JsonArray>
 * <EMBED CLASS='external-html' DATA-FILE-ID=JE_FIELD_BIND>
 */
@Torello.JavaDoc.CSSLinks(FileNames="JSONExceptions.css")
public abstract class JsonBindingException extends JsonException
{
    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDEX>  */
    public static final long serialVersionUID = 1;

    /**
     * <EMBED CLASS='external-html' DATA-FILE-ID=EXPF>
     * 
     * <BR /><BR />This contains the actual {@link JsonStructure} (which should either be an
     * instance of <B>{@link JsonObject}</B> or <B>{@link JsonArray}</B>) which contained the
     * array-element or object-property that has caused this exception throw.
     */
    public final JsonStructure errorSourceJsonStruct;

    /**
     * <EMBED CLASS='external-html' DATA-FILE-ID=EXPF>
     * 
     * <BR /><BR />This contains the <B STYLE='color: red;'>expected type</B> which ought to have
     * been found at the user-specified <B>{@link JsonArray}</B> or <B>{@link JsonObject}</B>
     * location.  Since both of these kinds of <B>{@link JsonStructure}</B> are only allowed to
     * have <B STYLE='color: red;'>Json-Type's</B>; therefore this field's declared type is 
     * <B>{@link JsonValue.ValueType}</B>.
     * 
     * <BR /><BR /><B STYLE='color: red;'>ASIDE:</B> The enum <B>{@link JsonValue.ValueType}</B>
     * has two enum-constants which represent the <B STYLE='color: red'>Json-Type</B>
     * 'Boolean'.  As a result, there are two possible values to which this field could be
     * assigned to symbolize a <B>Json Boolean Type</B> ({@link JsonValue.ValueType#FALSE} and
     * {@link JsonValue.ValueType#TRUE}).  However, in Java HTML, a Json-Boolean Type will always
     * be represented using the {@code TRUE} enum-constant.
     */
    public final JsonValue.ValueType expectedJsonType;

    /**
     * <EMBED CLASS='external-html' DATA-FILE-ID=EXPF>
     * 
     * <BR /><BR />This is the value retrieved from the <B>{@link JsonArray}</B> or
     * <B>{@link JsonObject}</B>.  If the value was not present or unavailable, then this parameter
     * will, indeed, evaulated to <B STYLE='color: red;'>Java-Null</B>.
     * If <B STYLE='color: red;'>Json-Null</B> was retrieved, then this parameter will contain
     * <B>{@link JsonValue#NULL}</B>.
     */
    public final JsonValue valueRetrieved;

    /**
     * <EMBED CLASS='external-html' DATA-FILE-ID=EXPF>
     * 
     * <BR /><BR />This specifies <B STYLE='color: red;'>return type</B> (as an instance of
     * <B>{@code java.lang.Class<T>}</B> that is used by the method which has thrown this
     * exception.  This is the <B STYLE='color:red'>Java-Type</B> to which the 
     * <B STYLE='color:red'>Json-Type</B> was going to be assigned.
     */
    public final Class<?> methodReturnJavaType;

    /**
     * Constructs a {@code JsonBindingException} with no specified detail messsage,
     * and the user-provided convenience-field values.
     * 
     * @param errorSourceJsonStruct <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_ESJS>
     * @param expectedJsonType      <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_EJT>
     * @param valueRetrieved        <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_VR>
     * @param methodReturnJavaType  <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_MRJT>
     */
    /** Constructs a {@code JsonBindingException} with no detail message. */
    public JsonBindingException(
            JsonStructure       errorSourceJsonStruct,
            JsonValue.ValueType expectedJsonType,
            JsonValue           valueRetrieved,
            Class<?>            methodReturnJavaType
        )
    {
        super(
            BASE_MESSAGE(
                errorSourceJsonStruct, expectedJsonType, valueRetrieved,
                methodReturnJavaType
            ));

        this.errorSourceJsonStruct  = errorSourceJsonStruct;
        this.expectedJsonType       = expectedJsonType;
        this.valueRetrieved         = valueRetrieved;
        this.methodReturnJavaType   = methodReturnJavaType;
    }

    /**
     * Constructs a {@code JsonBindingException} with the specified detail message, and
     * user-provided convenience-field values.
     * 
     * @param message the detail message.
     * @param errorSourceJsonStruct <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_ESJS>
     * @param expectedJsonType      <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_EJT>
     * @param valueRetrieved        <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_VR>
     * @param methodReturnJavaType  <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_MRJT>
     */
    public JsonBindingException(
            String              message,
            JsonStructure       errorSourceJsonStruct,
            JsonValue.ValueType expectedJsonType,
            JsonValue           valueRetrieved,
            Class<?>            methodReturnJavaType
        )
    {
        super(message);

        this.errorSourceJsonStruct  = errorSourceJsonStruct;
        this.expectedJsonType       = expectedJsonType;
        this.valueRetrieved         = valueRetrieved;
        this.methodReturnJavaType   = methodReturnJavaType;
    }

    /**
     * Constructs a new {@code JsonBindingException} with the specified detail message and cause.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>NOTE:</B>
     * 
     * <BR /><BR />The detail message associated with cause is not automatically incorporated into
     * this exception's detail message.
     * 
     * @param message The detail message (which is saved for later retrieval by the
     * {@code Throwable.getMessage()} method).
     * 
     * @param cause the cause (which is saved for later retrieval by the
     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
     * cause is nonexistent or unknown.)
     * 
     * @param errorSourceJsonStruct <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_ESJS>
     * @param expectedJsonType      <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_EJT>
     * @param valueRetrieved        <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_VR>
     * @param methodReturnJavaType  <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_MRJT>
     */
    public JsonBindingException(
            String              message,
            Throwable           cause,
            JsonStructure       errorSourceJsonStruct,
            JsonValue.ValueType expectedJsonType,
            JsonValue           valueRetrieved,
            Class<?>            methodReturnJavaType
        )
    {
        super(message, cause);

        this.errorSourceJsonStruct  = errorSourceJsonStruct;
        this.expectedJsonType       = expectedJsonType;
        this.valueRetrieved         = valueRetrieved;
        this.methodReturnJavaType   = methodReturnJavaType;
    }

    /**
     * Constructs a new {@code JsonBindingException} with the specified cause and a detail message of
     * {@code (cause==null ? null : cause.toString())} (which typically contains the class and
     * detail message of cause).
     * 
     * <BR /><BR />This constructor is useful for exceptions that are little more than wrappers for
     * other throwables.
     * 
     * @param cause The cause (which is saved for later retrieval by the
     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
     * cause is nonexistent or unknown.)
     * 
     * @param errorSourceJsonStruct <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_ESJS>
     * @param expectedJsonType      <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_EJT>
     * @param valueRetrieved        <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_VR>
     * @param methodReturnJavaType  <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_MRJT>
     */
    public JsonBindingException(
            Throwable           cause,
            JsonStructure       errorSourceJsonStruct,
            JsonValue.ValueType expectedJsonType,
            JsonValue           valueRetrieved,
            Class<?>            methodReturnJavaType
        )
    {
        super(
            BASE_MESSAGE(
                errorSourceJsonStruct, expectedJsonType, valueRetrieved,
                methodReturnJavaType, cause
            ),
            cause
        );

        this.errorSourceJsonStruct  = errorSourceJsonStruct;
        this.expectedJsonType       = expectedJsonType;
        this.valueRetrieved         = valueRetrieved;
        this.methodReturnJavaType   = methodReturnJavaType;
    }

    // Package Visible Exception Message Helper
    static String ABBREV_STRUCT(JsonStructure js)
    {
        return (js != null) 
            ? StrPrint.abbrevEnd(js.toString().trim(), true, MAX_STR_LEN)
            : "Null Was Passed";
    }

    private static final String JVVT_NAME = "JsonValue.ValueType.";
    private static int MAX_STR_LEN = 70;

    // Package Visible Exception Message Helper
    static String JT_STR(JsonValue.ValueType jt)
    {
        if (jt == null) return "Json-Type Not Available";

        switch (jt)
        {
            case ARRAY:     return JVVT_NAME + "ARRAY";
            case FALSE:     return JVVT_NAME + "FALSE";
            case NULL:      return JVVT_NAME + "NULL";
            case NUMBER:    return JVVT_NAME + "NUMBER";
            case OBJECT:    return JVVT_NAME + "OBJECT";
            case STRING:    return JVVT_NAME + "STRING";
            case TRUE:      return JVVT_NAME + "TRUE";
            default:        throw new Torello.Java.UnreachableError();
        }
    }

    // Package Visible Exception Message Helper
    static String ABBREV_VAL(JsonValue valueRetrieved)
    {
        if (valueRetrieved == null) return "Java-Null (Not Present)";

        if (valueRetrieved.getValueType() == JsonValue.ValueType.NULL)
            return "JsonValue.NULL (Json-Null)";

        return StrPrint.abbrevEnd(valueRetrieved.toString().trim(), true, MAX_STR_LEN);
    }

    static String CAUSE_MESSAGE(Throwable[] causes)
    {
        if ((causes == null) || (causes.length == 0)) return "";

        String temp = causes[0].getMessage().trim();

        String seeDetailsMessage = ((temp.length() > MAX_STR_LEN) || (temp.indexOf('\n') != -1))
            ? "\tSee Throwable.cause():    [The message has been abbreviated]\n"
            : "";

        return
            "\tCause-Exception Class:    " + causes[0].getClass().getName() + "\n" +
            "\tCause-Exception Message:  " +
                StrPrint.abbrevEnd(temp, true, MAX_STR_LEN) + "\n" +
            seeDetailsMessage;
    }

    /**
     * A simple helper method for printing a consistent error messge using the input-data
     * convenience fields.
     * 
     * @param errorSourceJsonStruct <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_ESJS>
     * @param expectedJsonType      <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_EJT>
     * @param valueRetrieved        <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_VR>
     * @param methodReturnJavaType  <EMBED CLASS='external-html' DATA-FILE-ID=JBEX_MRJT>
     * @param causes                Optional Parameter.  At most 1 cause is printed.
     * 
     * @return The error message {@code String}.
     */
    protected static String BASE_MESSAGE(
            JsonStructure       errorSourceJsonStruct,
            JsonValue.ValueType expectedJsonType,
            JsonValue           valueRetrieved,
            Class<?>            methodReturnJavaType,
            Throwable...        causes
        )
    {
        return
            "Problems Binding Json\n" +
            CAUSE_MESSAGE(causes) +
            "\tFound In JsonStructure:   " + ABBREV_STRUCT(errorSourceJsonStruct) + "\n" +
            "\tJsonStructure SubClass:   " + errorSourceJsonStruct.getClass().getSimpleName() + "\n" +
            "\tExpected Json-Type:       " + JT_STR(expectedJsonType) + "\n" +
            "\tContained JsonValue:      " + ABBREV_VAL(valueRetrieved) + "\n" +
            "\tHaving Actual Json-Type:  " + JT_STR((valueRetrieved != null)
                    ? valueRetrieved.getValueType()
                    : null
                ) + "\n" +
            "\tConverting To Java-Type: " + ((methodReturnJavaType != null)
                    ? methodReturnJavaType.getCanonicalName()
                    : "Java-Type Unknown"
                );
    }
}