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
package Torello.Browser;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class BuildInstance
{
    @SuppressWarnings("unchecked")
    static <T extends BaseType<T>> T build(
            final NestedDescriptor<T>   descriptor,
            final Object[]              assignments,
            final boolean[]             assigned
        )
    {
        // descriptor's are singleton instances, and they are generated by a Code Generator.  The
        // likelihood that this ever throws should be absolutely ZERO !!  However, doing this check
        // is almost free (it is just two simple if-statements), so there is no sense in removing 
        // these safety checks.
        // 
        // It would be a serious mistake on my part / the developer's side of things if these two 
        // invariants ever broke (if for whatever reason they were to)

        if (descriptor.size != assignments.length) throw new BuildInstanceError(
            "descriptor.size    = " + descriptor.size + '\n' +
            "assignments.length = " + assignments.length + '\n',
            descriptor

        );

        if (assignments.length != assigned.length) throw new BuildInstanceError(
            "assignments.length = " + assignments.length + '\n' +
            "assigned.legth     = " + assigned.length,
            descriptor
        );


        // This exception throw IS NOT a 'BuildInstanceError'
        // This exception check is looking for user error, not programmer error, or misplaced
        // assumptions.

        for (int i=0; i < descriptor.size; i++)
            if (assigned[i] == false)
                if (descriptor.optionals.get(i) == false)
                    throw new NullNonOptionalException(
                        "Parameter '" + descriptor.names.get(i) + "' is not optional, " +
                        "but it hasn't been assigned a value either."
                    );

        final Constructor<T> ctor;

        if (descriptor.ctor != null) ctor = descriptor.ctor;

        else try 
        {
            @SuppressWarnings("rawtypes")
            final Constructor[] ctorArr = descriptor.baseTypeClass.getConstructors();

            if (ctorArr == null) throw new BuildInstanceError
                ("getConstructors() has returned a null Constructor[] Array", descriptor);

            if (ctorArr.length != 1) throw new BuildInstanceError (
                "getConstructors() has returned a Constructor[] Array having a length other " +
                "than 1 (length:" + ctorArr.length + ")",
                descriptor
            );

            ctor = (Constructor<T>) ctorArr[0];

            if (ctor == null) throw new BuildInstanceError
                ("getConstructors() has returned an array with a null entry", descriptor);
        }

        catch (SecurityException e)
        {
            throw new BuildInstanceError(
                "There was an error extracting the constructor from this type's Class.  Please " +
                "see the getCause() throwale for details.",
                descriptor,
                e
            );
        }

        if (ctor.getParameterCount() != descriptor.size) throw new BuildInstanceError(
            "The number of parameters in the constructor which was retrieved from class:\n" +
            '[' + descriptor.baseTypeClass.getCanonicalName() + "]\n" +
            "is " + ctor.getParameterCount() + ", but the number of fields listed in the class " +
            "according to the class' descriptor is " + descriptor.size + ".  These numbers " +
            "should be equal.",
            descriptor
        );

        try 
            { return ctor.newInstance(assignments); }

        catch (IllegalAccessException | InstantiationException | InvocationTargetException | 
            ExceptionInInitializerError e)
        {
            throw new BuildInstanceError
                ("There was an error invoking this type's constructor", descriptor, e);
        }
    }


    // The errors that are thrown by this class are all tantamount to "assertion errors"
    // There should be absolutely zero chance that any of them ever throw.
    // If they do throw, it is wholly a result of a mistake in the code or a misplaced assuption
    // regarding how Java's reflection works.
    // 
    // I've been doing this for a very long time, and generally these exceptions never throw.  
    // They are checked exceptions, so they must be inside of try-catch clauses.  It's best to 
    // catch them, and wrap them in some kind of unchecked throwable.  This generally works fine, 
    // but there is no need to make a public spectacle out of this "BuildIntanceError"

    private static class BuildInstanceError extends Error 
    {
        protected static final long serialVersionUID = 1;

        private BuildInstanceError(
                final String                message,
                final NestedDescriptor<?>   descriptor
            )
        {
            super(
                message + '\n' +
                "Currently Building Type: " + descriptor.baseTypeClass.getCanonicalName()
            );
        }

        private BuildInstanceError(
                final String                message,
                final NestedDescriptor<?>   descriptor,
                final Throwable             cause
            )
        {
            super(
                message + '\n' +
                "Currently Building Type: " + descriptor.baseTypeClass.getCanonicalName(),
                cause
            );
        }
    }
}