001package Torello.JSON; 002 003import Torello.Java.StringParse; 004 005import java.lang.reflect.Array; 006 007import javax.json.JsonArray; 008import javax.json.JsonValue; 009 010import java.util.Arrays; 011import java.util.Objects; 012 013import static javax.json.JsonValue.ValueType.*; 014 015@Torello.JavaDoc.Annotations.StaticFunctional 016public class ProcessMultiDimJsonArray 017{ 018 private ProcessMultiDimJsonArray() { } 019 020 /** 021 * This class is invoked by the class {@link RJArrDimN} 022 * 023 * @param <BASIC_TYPE> The "Component Type" of the Output-Array. 024 * 025 * @param <STREAM_TYPE> The "Intermediate Stream Type", which is present before the conversion 026 * to an Array. 027 * 028 * @param <RETURN_ARR_TYPE> The actual Return-Type of the method. This must be an Array-Class, 029 * such as {@code int[][].class} or (in the case of Boxed-Type Arrays) {@code Integer[][]}. 030 * 031 * @param ja Any instance of {@link JsonArray}. The contents sof this array should match the 032 * dimensionality of the expected Output-Array Type, or an exception will likelyy throw. 033 * 034 * @param rec An instance of {@link SettingsRec} that's been configured to return a 035 * multi-dimensional array. 036 * 037 * @param retArrClass The class of the return array. 038 * @return An instance of {@code 'retArrClass'} 039 */ 040 public static <BASIC_TYPE, STREAM_TYPE, RETURN_ARR_TYPE> RETURN_ARR_TYPE jsonArrayToJava( 041 final JsonArray ja, 042 final SettingsRec<BASIC_TYPE, STREAM_TYPE> rec, 043 final Class<RETURN_ARR_TYPE> retArrClass 044 ) 045 { 046 CHECK_ARRAY_CLASS(retArrClass, rec.CLASS); 047 return jsonArrayToJava_INTERNAL(ja, rec, retArrClass); 048 } 049 050 @SuppressWarnings("unchecked") 051 private static <BASIC_TYPE, STREAM_TYPE, RETURN_ARR_TYPE> RETURN_ARR_TYPE 052 jsonArrayToJava_INTERNAL( 053 final JsonArray ja, 054 final SettingsRec<BASIC_TYPE, STREAM_TYPE> rec, 055 final Class<RETURN_ARR_TYPE> retArrClass 056 ) 057 { 058 /* 059 System.out.println( 060 "TOP-OF-METHOD-PART INTERIM PRINTING:\n" + 061 "retArrClass.getSimpleName(): " + retArrClass.getSimpleName() + '\n' + 062 "ja.toString(): " + ja.toString() 063 ); 064 */ 065 066 // If this is requesting a one-dimensional array, get it using the 1D-Generator, 067 // and simply return that array. This requires a cast because there is no way to prove 068 // to the Java-Compiler that <T> is equal to any return-value at all. 069 // 070 // Remember that this is only guaranteed (it works!) because the helper methods are all 071 // protected or private, and it has been guaranteed through rigorous testing, and 072 // preventing the user from playing with it! 073 074 if (StringParse.countCharacters(retArrClass.getSimpleName(), '[') == 1) 075 return (RETURN_ARR_TYPE) rec.array1DGenerator.apply(ja); 076 077 078 // Otherwise, this is not a single-dimension (1D) array. Instead, the JsonArray needs 079 // to be iterated, and this method called, recursively, on each of the sub-arrays. 080 // 081 // NOTE: 'compClass' will also be an array, but with one fewer dimensions 082 083 final Class<?> componentClass = retArrClass.getComponentType(); 084 final int SIZE = ja.size(); 085 086 087 // This generates an instance of the "Array Component Type". All that means is that this 088 // new array has one fewer set of brackets. int[][] would become int[] 089 090 final RETURN_ARR_TYPE retArr = (RETURN_ARR_TYPE) Array.newInstance(componentClass, SIZE); 091 092 JsonValue jv = null; 093 094 for (int i=0; i < SIZE; i++) 095 096 switch ((jv = ja.get(i)).getValueType()) 097 { 098 // javax.json.JsonValue.ValueType.NULL 099 case NULL: Array.set(retArr, i, null); break; 100 101 // javax.json.JsonValue.ValueType.ARRAY (JsonArray) 102 case ARRAY: 103 104 final Object newArr = 105 jsonArrayToJava_INTERNAL((JsonArray) jv, rec, componentClass); 106 107 /* 108 // assign these variables using some kind of "if-then-else" and "toString" 109 // In order to use java.util.Arrays.toString(), you will need to actual type of 110 // othese objects, and those Parameterized Types are not easy to use with 111 // java.util.Arrays 112 113 final String RET_ARR_STR, NEW_ARR_STR; 114 115 System.out.println( 116 "retArrClass: " + retArrClass.getSimpleName() + '\n' + 117 "retArr: " + RET_ARR_STR + '\n' + 118 "compClass: " + componentClass.getSimpleName() + '\n' + 119 "newArr: " + NEW_ARR_STR + '\n' + 120 "i: " + i + '\n' + 121 "SIZE: " + SIZE + '\n' + 122 "jv: " + jv.toString() + '\n' 123 ); 124 */ 125 126 Array.set(retArr, i, newArr); 127 128 break; 129 130 // javax.json.JsonValue.ValueType.TRUE, FALSE, NUMBER, STRING, OBJECT 131 default: 132 133 if (rec.IN_NSAT) Array.set(retArr, i, null); 134 else if (rec.S_NSAT) continue; 135 else throw new JsonTypeArrException(ja, i, ARRAY, jv, retArrClass); 136 } 137 138 return retArr; 139 } 140 141 142 143 // ******************************************************************************************** 144 // ******************************************************************************************** 145 // One Helper 146 // ******************************************************************************************** 147 // ******************************************************************************************** 148 149 150 /** 151 * Check user input, and throws exceptions if the array-class has not been properly 152 * chosen. 153 * 154 * @param retArrClass This must be a primitive-array class, possibly of multiple dimensions 155 * 156 * @param expectedRootClass The expected "root class". For {@code int[][].class}, the root 157 * class would be {@code int.class}. 158 * 159 * @return Parameter {@code retArrClass} is the return value of this checker method 160 * 161 * @throws IllegalArgumentExcetion If parameter retArrClass: 162 * If calling retArrClass.isArray() returns FALSE 163 * If the root-array type is not the appropriate type for the method that was called 164 */ 165 protected static <T> Class<T> CHECK_ARRAY_CLASS( 166 final Class<T> retArrClass, 167 final Class<?> expectedRootClass 168 ) 169 { 170 Objects.requireNonNull(retArrClass, "Return-Array Type, Parameter 'retArrClass' is null"); 171 172 if (! retArrClass.isArray()) throw new IllegalArgumentException( 173 "The class you have passed to parameter 'retArrClass' " + 174 "[" + retArrClass.getSimpleName() + "], is not an array" 175 ); 176 177 Class<?> componentClass = retArrClass.getComponentType(); 178 179 while (componentClass.isArray()) componentClass = componentClass.getComponentType(); 180 181 if (! expectedRootClass.equals(componentClass)) throw new IllegalArgumentException( 182 "The class you have passed to parameter 'retArrClass' " + 183 "[" + retArrClass.getSimpleName() + "], is not a(n) " + 184 expectedRootClass.getSimpleName() + "-array." 185 ); 186 187 return retArrClass; 188 } 189}