Skip to content

Commit 974fcf1

Browse files
committed
Implement JxDecoder.parseString(...), JxDecoder.parseNumber(...), JxDecoder.parseBoolean(...), JxDecoder.parse(...), re #61
1 parent ddc13af commit 974fcf1

31 files changed

+488
-211
lines changed

generator/src/main/java/org/jsonx/Member.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ final Class<?> validateTypeBinding() {
229229
if (!(e.getCause() instanceof ClassNotFoundException))
230230
throw e;
231231

232-
if (logger.isWarnEnabled()) { logger.warn("Unable to validate \"decode\": " + typeBinding.decode + " due to: " + e.getCause().getMessage()); }
232+
if (logger.isWarnEnabled()) { logger.warn("Unable to validate \"decode\": " + typeBinding.decode + " due to: " + e.getMessage()); }
233233
}
234234
}
235235

@@ -243,7 +243,7 @@ final Class<?> validateTypeBinding() {
243243
if (!(e.getCause() instanceof ClassNotFoundException))
244244
throw e;
245245

246-
if (logger.isWarnEnabled()) { logger.warn("Unable to validate \"encode\": " + typeBinding.encode + " due to: " + e.getCause().getMessage()); }
246+
if (logger.isWarnEnabled()) { logger.warn("Unable to validate \"encode\": " + typeBinding.encode + " due to: " + e.getMessage()); }
247247
}
248248
}
249249

generator/src/main/java/org/jsonx/NumberModel.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.IdentityHashMap;
2323

2424
import org.jaxsb.runtime.Bindings;
25+
import org.jsonx.Registry.Type;
2526
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$CodecTypeFieldBinding;
2627
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$FieldBinding;
2728
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$FieldIdentifier;
@@ -267,18 +268,21 @@ Registry.Type typeDefault(final boolean primitive) {
267268
@Override
268269
@SuppressWarnings("unchecked")
269270
String isValid(final Bind.Type typeBinding) {
270-
if (typeBinding.type == null)
271+
final Type type = typeBinding.type;
272+
if (type == null)
271273
return null;
272274

273-
if ((scale != Integer.MAX_VALUE || range != null) && !registry.getType(Number.class).isAssignableFrom(typeBinding.type))
274-
return "Constraint definitions in \"" + (name() != null ? name() : id()) + "\" are not enforcable with type binding \"" + typeBinding.type + "\" for \"" + elementName() + "\"; either choose a type binding that is assignable to " + defaultClass() + ", or remove the constraint definitions";
275+
if ((scale != Integer.MAX_VALUE || range != null) && !registry.getType(Number.class).isAssignableFrom(type)) {
276+
final boolean x = registry.getType(Number.class).isAssignableFrom(type);
277+
return "Constraint definitions in \"" + (name() != null ? name() : id()) + "\" are not enforcable with type binding \"" + type + "\" for \"" + elementName() + "\"; either choose a type binding that is assignable to " + defaultClass() + ", or remove the constraint definitions";
278+
}
275279

276280
if (scale == 0)
277281
return null;
278282

279-
final Class<?> cls = Classes.forNameOrNull(typeBinding.type.getNativeName(), false, getClass().getClassLoader());
283+
final Class<?> cls = Classes.forNameOrNull(type.getNativeName(), false, getClass().getClassLoader());
280284
if (cls != null && defaultClass().isAssignableFrom(cls) && Numbers.isWholeNumberType((Class<? extends Number>)cls))
281-
return "The decimal \"number\" with scale=" + scale + " in \"" + (name() != null ? name() : id()) + "\" cannot be represented with the whole numeric type: " + typeBinding.type.name;
285+
return "The decimal \"number\" with scale=" + scale + " in \"" + (name() != null ? name() : id()) + "\" cannot be represented with the whole numeric type: " + type.name;
282286

283287
return null;
284288
}

generator/src/main/java/org/jsonx/Registry.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,11 @@ class Type {
158158
this.canonicalPackageName = canonicalPackageName.length() == 0 ? null : canonicalPackageName;
159159
this.compositeName = compositeName;
160160
this.name = isDefaultPackage ? compositeName : packageName + "." + compositeName;
161+
161162
this.canonicalCompositeName = Classes.toCanonicalClassName(compositeName);
162163
this.simpleName = canonicalCompositeName.substring(canonicalCompositeName.lastIndexOf('.') + 1);
163164
this.canonicalName = isDefaultPackage ? canonicalCompositeName : packageName + "." + canonicalCompositeName;
164-
this.cls = Classes.forNameOrNull(name, false, ClassLoader.getSystemClassLoader());
165+
this.cls = Classes.forNameOrNull(name, false, Thread.currentThread().getContextClassLoader());
165166
if (superType == null && this.cls != null && this.cls != Object.class) {
166167
superType = cls.getSuperclass() == null ? null : getType(cls.getSuperclass());
167168
this.superType = OBJECT.equals(superType) ? null : superType;

generator/src/main/java/org/jsonx/SchemaElement.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
import org.jsonx.www.schema_0_5.xL0gluGCXAA.Schema.TargetNamespace$;
5858
import org.libj.lang.PackageLoader;
5959
import org.libj.lang.PackageNotFoundException;
60-
import org.libj.lang.WrappedArrayList;
60+
import org.libj.lang.ToArrayList;
6161
import org.libj.util.Iterators;
6262
import org.openjax.json.JsonReader;
6363
import org.openjax.xml.api.CharacterDatas;
@@ -451,7 +451,7 @@ private SchemaElement(final HashMap<String,Registry> namespaceToRegistry, final
451451
private ArrayList<Model> rootMembers() {
452452
final Collection<Model> models = registry.getModels();
453453
if (models.size() == 0)
454-
return WrappedArrayList.EMPTY_LIST;
454+
return ToArrayList.EMPTY_LIST;
455455

456456
final ArrayList<Model> members = new ArrayList<>();
457457
for (final Model model : models) // [C]

generator/src/test/java/org/jsonx/IncludeModelTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public static URL[] resources() throws IOException {
5959

6060
@Test
6161
public void test() throws IOException {
62-
final String name = URLs.getSimpleName(resource);
62+
final String name = URLs.getNameWithoutExtension(resource);
6363
final URL jsb = URLs.create(URLs.getCanonicalParent(resource), name + ".jsb");
6464
test(name, resource, jsb);
6565
}

generator/src/test/java/org/jsonx/ModelTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,8 @@ private static void assertSources(final Map<String,String> expected, final Map<S
237237

238238
static void test(final URL resource) throws CompilationException, DecodeException, IOException, PackageNotFoundException, SAXException {
239239
final String fileName = URLs.getName(resource);
240-
final String namespace = "urn:test:" + StringPaths.getSimpleName(fileName);
241-
final String packageName = namespacePackage + StringPaths.getSimpleName(fileName);
240+
final String namespace = "urn:test:" + StringPaths.getNameWithoutExtension(fileName);
241+
final String packageName = namespacePackage + StringPaths.getNameWithoutExtension(fileName);
242242
final String pkg = packageName + ".";
243243

244244
final $AnyType<?> control = Bindings.parse(resource);

generator/src/test/resources/binding/datatype.jsbx

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@
8181
<number name="byte" scale="0" range="[-64,63]" doc="Primitive byte type"/>
8282
<number name="Short" scale="0" range="[-16384,16383]" doc="Short number type"/>
8383
<number name="StringDecimal"/>
84-
<number name="numRange" range="[10000000000,]" doc="Template for number type with range"/>
85-
<number name="numRangePrimitive" range="[10000000000,]" doc="Template for number type with range"/>
84+
<number name="numRange" range="[100000,]" doc="Template for number type with range"/>
85+
<number name="numRangePrimitive" range="[100000,]" doc="Template for number type with range"/>
8686
<number name="cachedInteger" scale="0" range="[1,]" doc="Template for integer number type with range"/>
8787
<number name="cachedIntegerPrimitive" scale="0" range="[1,]" doc="Template for integer number type with range"/>
8888
<number name="plainDecimal" scale="2" doc="Template cached BigDecimal"/>

generator/src/test/resources/schema/account.jsdx

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<property name="firstName" xsi:type="string" nullable="false"/>
3939
<property name="lastName" xsi:type="string" nullable="false"/>
4040
</object>
41+
4142
<array name="accounts">
4243
<reference type="account"/>
4344
</array>

jsonx-maven-plugin/src/test/java/org/jsonx/ArrayCreateIterator.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ int nextIndex() throws IOException {
4747

4848
@Override
4949
void next() throws IOException {
50-
current = this;
50+
offLen0 = this;
5151
++cursor;
5252
}
5353

@@ -68,38 +68,38 @@ int previous() {
6868
Error validate(final Annotation annotation, final int index, final Relations relations, final IdToElement idToElement, final Class<? extends Codec> codecType, final boolean validate, final TriPredicate<JxObject,String,Object> onPropertyDecode) throws IOException {
6969
lastIndex = index;
7070
if (trialType == TrialType.NULLABLE) {
71-
current = null;
71+
offLen0 = null;
7272
}
7373
else if (annotation instanceof StringElement) {
7474
final StringElement element = (StringElement)annotation;
75-
current = element.nullable() && Math.random() < 0.5 ? null : StringTrial.createValid(element.type(), element.decode(), element.pattern());
75+
offLen0 = element.nullable() && Math.random() < 0.5 ? null : StringTrial.createValid(element.type(), element.decode(), element.pattern());
7676
}
7777
else if (annotation instanceof NumberElement) {
7878
final NumberElement element = (NumberElement)annotation;
79-
current = element.nullable() && Math.random() < 0.5 ? null : NumberTrial.createValid(element.type(), element.decode(), element.range(), element.scale());
79+
offLen0 = element.nullable() && Math.random() < 0.5 ? null : NumberTrial.createValid(element.type(), element.decode(), element.range(), element.scale());
8080
}
8181
else if (annotation instanceof ObjectElement) {
8282
final ObjectElement element = (ObjectElement)annotation;
83-
current = element.nullable() && Math.random() < 0.5 ? null : ObjectTrial.createValid(element.type());
83+
offLen0 = element.nullable() && Math.random() < 0.5 ? null : ObjectTrial.createValid(element.type());
8484
}
8585
else if (annotation instanceof ArrayElement) {
8686
final ArrayElement element = (ArrayElement)annotation;
87-
current = element.nullable() && Math.random() < 0.5 ? null : ArrayTrial.createValid(element.type(), element.minIterate(), element.maxIterate(), element.elementIds(), idToElement);
87+
offLen0 = element.nullable() && Math.random() < 0.5 ? null : ArrayTrial.createValid(element.type(), element.minIterate(), element.maxIterate(), element.elementIds(), idToElement);
8888
}
8989
else if (annotation instanceof BooleanElement) {
9090
final BooleanElement element = (BooleanElement)annotation;
91-
current = element.nullable() && Math.random() < 0.5 ? null : BooleanTrial.createValid(element.type(), element.decode());
91+
offLen0 = element.nullable() && Math.random() < 0.5 ? null : BooleanTrial.createValid(element.type(), element.decode());
9292
}
9393
else if (annotation instanceof AnyElement) {
9494
final AnyElement element = (AnyElement)annotation;
9595
if (element.nullable() && Math.random() < 0.5) {
96-
current = null;
96+
offLen0 = null;
9797
}
9898
else {
9999
AnyTrial.createValid(element, new PentaConsumer<Object,Class<?>,String,String,Annotation>() {
100100
@Override
101101
public void accept(final Object value, final Class<?> type, final String decode, final String encode, final Annotation typeAnnotation) {
102-
ArrayCreateIterator.this.current = value;
102+
ArrayCreateIterator.this.offLen0 = value;
103103
}
104104
});
105105
}
@@ -108,7 +108,7 @@ public void accept(final Object value, final Class<?> type, final String decode,
108108
throw new UnsupportedOperationException("Unsupported annotation type: " + annotation.annotationType().getName());
109109
}
110110

111-
relations.set(index, current, annotation);
111+
relations.set(index, offLen0, annotation);
112112
return null;
113113
}
114114
}

jsonx-maven-plugin/src/test/java/org/jsonx/Asserting.java

+19-5
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
abstract class Asserting {
2727
static final Logger logger = LoggerFactory.getLogger(Asserting.class);
2828

29-
static void assertEquals(final String message, final Object expected, final Object actual) {
29+
static boolean assertEquals(final String message, final Object expected, final Object actual) {
3030
if ((expected == null) != (actual == null))
3131
Assert.assertEquals(message, expected, actual);
3232

3333
if (expected == null || actual == null)
34-
return;
34+
return true;
3535

3636
final boolean equals = ObjectUtil.equals(expected, actual);
3737
if (!equals) {
@@ -42,8 +42,20 @@ static void assertEquals(final String message, final Object expected, final Obje
4242
System.err.println(ObjectUtil.toString(actual));
4343
if (expected.getClass().isArray())
4444
Assert.assertTrue(message, equals);
45-
else
45+
else {
46+
if (!expected.equals(actual)) {
47+
expected.equals(actual);
48+
expected.equals(actual);
49+
expected.equals(actual);
50+
expected.equals(actual);
51+
expected.equals(actual);
52+
expected.equals(actual);
53+
expected.equals(actual);
54+
return false;
55+
}
56+
4657
Assert.assertEquals(message, expected, actual);
58+
}
4759
}
4860

4961
final int expectedHashCode = ObjectUtil.hashCode(expected);
@@ -56,10 +68,12 @@ static void assertEquals(final String message, final Object expected, final Obje
5668
System.err.println(ObjectUtil.toString(actual));
5769
Assert.assertEquals(message, expectedHashCode, actualHashCode);
5870
}
71+
72+
return true;
5973
}
6074

61-
static void assertEquals(final Object expected, final Object actual) {
62-
assertEquals(null, expected, actual);
75+
static boolean assertEquals(final Object expected, final Object actual) {
76+
return assertEquals(null, expected, actual);
6377
}
6478

6579
static void assertNotEquals(final String message, final Object expected, final Object actual) {

jsonx-maven-plugin/src/test/java/org/jsonx/ClassTrial.java

+9-7
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,13 @@ private String testEncode(final PropertyTrial<?> trial, final Relations[] relati
162162
String value = null;
163163
Exception exception = null;
164164
try {
165-
final AtomicReference<Bounds> bounds = new AtomicReference<>();
165+
final AtomicReference<Bounds> boundsRef = new AtomicReference<>();
166166
final StringBuilder b = new StringBuilder();
167167
validEncoder.encodeObject(b, binding, (g, n, r, s, e) -> {
168168
if (g.equals(trial.getMethod) && trial.name.equals(n)) {
169-
if (bounds.get() != null)
170-
throw new IllegalStateException(String.valueOf(bounds.get()));
169+
final Bounds bounds = boundsRef.get();
170+
if (bounds != null)
171+
throw new IllegalStateException(String.valueOf(bounds));
171172

172173
if (r != null) {
173174
if (relations[0] != null)
@@ -177,14 +178,15 @@ private String testEncode(final PropertyTrial<?> trial, final Relations[] relati
177178
}
178179

179180
if (s != -1)
180-
bounds.set(new Bounds(g, n, s, e));
181+
boundsRef.set(new Bounds(g, n, s, e));
181182
}
182183
});
183184

184185
json = b.toString();
185186
testJsonx(json);
186187

187-
value = bounds.get() == null ? null : json.substring((int)bounds.get().start, (int)bounds.get().end);
188+
final Bounds bounds = boundsRef.get();
189+
value = bounds == null ? null : json.substring((int)bounds.start, (int)bounds.end);
188190
}
189191
catch (final Exception e) {
190192
exception = e;
@@ -268,8 +270,8 @@ private int invoke(final PropertyTrial<?> trial) throws Exception {
268270
final Relations[] relations = {null};
269271
final String json = testEncode(trial, relations);
270272
final JxObject decoded = testDecode(trial, relations, json);
271-
if (decoded != null)
272-
assertEquals(binding, decoded);
273+
if (decoded != null && !assertEquals(binding, decoded))
274+
testDecode(trial, relations, json); // For debugging
273275

274276
trial.setMethod.invoke(trial.object, before);
275277
return count;

jsonx-maven-plugin/src/test/java/org/jsonx/NumberTrial.java

+42-12
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Optional;
2525

2626
import org.libj.lang.Classes;
27+
import org.libj.lang.Numbers;
2728
import org.libj.lang.ParseException;
2829
import org.libj.math.SafeMath;
2930

@@ -74,33 +75,62 @@ static Object createValid(final Class<?> type, final String decode, final String
7475
}
7576

7677
private static Double makeValid(final Range range) {
78+
// if (range != null && range.toString().equals("[10000000000,]"))
79+
// System.err.println();
80+
// System.err.println("Range: " + range);
7781
if (range == null)
7882
return null;
7983

80-
if (range.getMax() == null) {
81-
final double x = range.getMin().doubleValue() + 1d;
82-
return x;
83-
}
84+
if (range.getMax() == null)
85+
return ensureHasFraction(ensureNotTooBig(range.getMin().doubleValue()) + 1d);
8486

8587
if (range.getMin() == null)
86-
return range.getMax().doubleValue() - 1d;
88+
return ensureHasFraction(ensureNotTooBig(range.getMax().doubleValue()) - 1d);
8789

88-
return ((range.getMax().doubleValue() - range.getMin().doubleValue()) * random.nextDouble()) + range.getMin().doubleValue();
90+
return ensureHasFraction(((range.getMax().doubleValue() - range.getMin().doubleValue()) * random.nextDouble()) + range.getMin().doubleValue());
8991
}
9092

9193
private static Double makeInvalid(final Range range) {
92-
return range.getMin() != null ? range.getMin().doubleValue() - 1d : range.getMax().doubleValue() + 1d;
94+
double ensureHasFraction = range.getMin() != null ? range.getMin().doubleValue() - 1d : ensureNotTooBig(range.getMax().doubleValue()) + 1d;
95+
// System.err.println(ensureHasFraction);
96+
return ensureHasFraction;
9397
}
9498

9599
private static Number setScale(final Double value, final int scale) {
96-
return scale == Integer.MAX_VALUE ? value : scale == 0 ? value.longValue() : SafeMath.round(value, scale, RoundingMode.FLOOR);
100+
return scale == Integer.MAX_VALUE || scale == Integer.MIN_VALUE ? value : scale == 0 ? value.longValue() : SafeMath.round(value, scale, RoundingMode.FLOOR);
97101
}
98102

99103
private static Number setScale(final BigDecimal value, final int scale) {
100-
return scale == Integer.MAX_VALUE ? value : scale == 0 ? value.longValue() : value.setScale(scale, RoundingMode.FLOOR);
104+
return scale == Integer.MAX_VALUE || scale == Integer.MIN_VALUE ? value : scale == 0 ? value.longValue() : value.setScale(scale, RoundingMode.FLOOR);
105+
}
106+
107+
private static float ensureNotTooBig(final float value) {
108+
return value % 1000000000;
109+
}
110+
111+
private static double ensureNotTooBig(final double value) {
112+
return value % 1000000000;
113+
}
114+
115+
private static float ensureHasFraction(final float value) {
116+
return ensureHasFraction(Numbers.isWhole(value) ? value + Math.ulp(value) : value);
117+
}
118+
119+
private static double ensureHasFraction(final double value) {
120+
return Numbers.isWhole(value) ? value + Math.ulp(value) : value;
101121
}
102122

103123
private static Object toProperForm(final Class<?> type, final String decode, final int scale, final Double value) {
124+
final Object properForm2 = toProperForm2(type, decode, scale, value);
125+
if (properForm2 instanceof Number && ((Number)properForm2).doubleValue() > 100000) {
126+
toProperForm2(type, decode, scale, value);
127+
// System.err.println("Proper form: " + properForm2);
128+
}
129+
130+
return properForm2;
131+
}
132+
133+
private static Object toProperForm2(final Class<?> type, final String decode, final int scale, final Double value) {
104134
final Number result;
105135
if (BigInteger.class.isAssignableFrom(type))
106136
result = BigInteger.valueOf(value == null ? random.nextLong() : value.longValue());
@@ -113,11 +143,11 @@ else if (type == Short.class || type == short.class)
113143
else if (type == Byte.class || type == byte.class)
114144
result = value == null ? (byte)random.nextInt() : value.byteValue();
115145
else if (type == Float.class || type == float.class)
116-
result = value == null ? random.nextFloat() * random.nextInt() : value.floatValue();
146+
result = ensureHasFraction(value == null ? ensureNotTooBig(random.nextFloat() * random.nextInt()) : value.floatValue());
117147
else if (BigDecimal.class.isAssignableFrom(type))
118-
result = setScale(value == null ? BigDecimal.valueOf(random.nextDouble() * random.nextLong()) : BigDecimal.valueOf(value), scale);
148+
result = setScale(value == null ? BigDecimal.valueOf(ensureHasFraction(ensureNotTooBig(random.nextDouble() * random.nextLong()))) : BigDecimal.valueOf(ensureHasFraction(value)), scale);
119149
else
120-
result = setScale(value == null ? random.nextDouble() * random.nextLong() : value, scale);
150+
result = ensureHasFraction((double)setScale(value == null ? ensureNotTooBig(random.nextDouble() * random.nextLong()) : value, scale));
121151

122152
if (decode != null && decode.length() > 0)
123153
return JsdUtil.invoke(JsdUtil.parseExecutable(decode, String.class), String.valueOf(result));

0 commit comments

Comments
 (0)