001package Torello.JSON;
002
003import java.lang.reflect.Constructor;
004import java.lang.reflect.Modifier;
005import java.util.Objects;
006
007import javax.json.JsonObject;
008
009/** 
010 * Used for Read Json method that attempt to build a Java POJO, but fail due to an inability to
011 * extract a valid constructor from the object.  When using a class' constructor as a builder,
012 * the required constructor must be one which accepts only one parameter.  That parameter must be 
013 * of type {@link javax.json.JsonObject}.
014 */
015public class InvalidClassException extends RuntimeException
016{
017    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDEX>  */
018    public static final long serialVersionUID = 1;
019
020    /** Constructs a {@code InvalidClassException} with no detail message. */
021    public InvalidClassException()
022    { super(); }
023
024    /**
025     * Constructs a {@code InvalidClassException} with the specified detail message.
026     * @param message the detail message.
027     */
028    public InvalidClassException(String message)
029    { super(message); }
030
031    /**
032     * Constructs a new {@code InvalidClassException} with the specified detail message
033     * and cause.
034     * 
035     * <BR /><BR /><DIV CLASS=JDHint>
036     * <B STYLE='color:red;'>Note:</B> The detail message associated with cause is not
037     * automatically incorporated into this exception's detail message.
038     * </DIV>
039     * 
040     * @param message The detail message (which is saved for later retrieval by the
041     * {@code Throwable.getMessage()} method).
042     * 
043     * @param cause the cause (which is saved for later retrieval by the
044     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
045     * cause is nonexistent or unknown.)
046     */
047    public InvalidClassException(String message, Throwable cause)
048    { super(message, cause); }
049
050    /**
051     * Constructs a new {@code InvalidClassException} with the specified cause and a detail
052     * message of {@code (cause==null ? null : cause.toString())} (which typically contains the
053     * class and detail message of cause).  This constructor is useful for exceptions that are
054     * little more than wrappers for other throwables.
055     * 
056     * @param cause The cause (which is saved for later retrieval by the
057     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
058     * cause is nonexistent or unknown.)
059     */
060    public InvalidClassException(Throwable cause)
061    { super(cause); }
062
063    /**
064     * Extracts a valid {@code java.lang.reflect.Constructor} instance for a constructor that
065     * accepts one arguement of type {@code JsonObject}.
066     *
067     * <BR /><BR />Throws if such an instance of {@code Constructor} cannot be found.
068     *
069     * @throws NullPointerException throws if parameter {@code 'c'} is null
070     * 
071     * @throws InvalidClassException throws if any errors occur when extracting the instance of
072     * {@code java.lang.reflect.Constructor}.  This method excepts &amp; attempts to extract a one
073     * argument constructor whose sole arguement is of type {@link JsonObject}.
074     */
075    public static <T> Constructor<T> check(Class<T> c)
076    {
077        final Constructor<T> ctor;
078
079        Objects.requireNonNull(c, "The Class<T> parameter 'c' has been passed null");
080
081        try
082        {
083            // This just gets a "Constructor" using Reflection.  The main point is that the
084            // Constructor must have exactly one parameter - and that parameter must have a
085            // type "JsonObject"  (basic java.lang.reflect stuff)
086            //
087            //System.out.println("c.getName:():" + c.getName());
088
089            ctor = c.getDeclaredConstructor(JsonObject.class);
090        }
091
092        catch (Exception e)
093        {
094            if (c.getEnclosingClass() != null)
095            {
096                int modifiers = c.getModifiers();
097
098                if ((! Modifier.isStatic(modifiers)) ||  (! Modifier.isPublic(modifiers)))
099
100                    throw new InvalidClassException(
101                        "Unable to retrieve POJO Constructor for class: " +
102                        "[" + c.getName() + "]\n" +
103                        "Your class appears to be a Nested-Class, however it has not been " +
104                        "declared public and static.  There is no way to retrieve a " +
105                        "1-Argument JsonObject Constructor for Nested-Type's unless the " +
106                        "type has been declared BOTH static AND public.\n" +
107                        "See Exception.getCause() for details.",
108                        e
109                    );
110
111                else throw new InvalidClassException(
112                    "There was a problem retrieving a one-argument, public, constructor for the " +
113                    "class you wish to instantiate.  See Exception.getCause() for details.",
114                    e
115                );
116            }
117
118            else throw new InvalidClassException(
119                "Unable to retrieve POJO Constructor for class: [" + c.getName() + "]\n" +
120                "Do you have a one-argument, public, constructor for this class?\n" +
121                "Does it accept a JsonObject in its parameter list?\n" +
122                "See Exception.getCause() for details.",
123                e
124            );
125        }
126
127
128        // If the user has requested a class that doesn't have that kind of constructor, then
129        // there is no way to build the object.  Throw an exception.
130
131        if (ctor == null) throw new InvalidClassException(
132            "The class which was passed to parameter 'c' [" + c.getName() + "] does not " +
133            "appear to have a constructor with precisely one parameter of type JsonObject.  " +
134            "c.getDeclaredConstructor(JsonObject.class) has returned null."
135        );
136
137        return ctor;
138    }
139}