Skip to content

Commit

Permalink
Complete support of type binding for "object", re #53
Browse files Browse the repository at this point in the history
  • Loading branch information
safris committed Nov 1, 2023
1 parent b885681 commit e36735a
Show file tree
Hide file tree
Showing 20 changed files with 317 additions and 297 deletions.
8 changes: 4 additions & 4 deletions generator/src/main/java/org/jsonx/AnyModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ private AnyModel(final Registry registry, final Declarer declarer, final $Array.
}

private AnyModel(final Registry registry, final Declarer declarer, final AnyProperty property, final Method getMethod, final String fieldName) {
super(registry, declarer, property.nullable(), property.use(), null, null);
super(registry, declarer, property.nullable(), property.use(), null, null, null);
final t[] types = property.types();
this.types = getMemberTypes(types);
final Class<?> requiredFieldType = types.length == 0 ? defaultClass() : getFieldType(types);
Expand All @@ -189,7 +189,7 @@ private AnyModel(final Registry registry, final Declarer declarer, final AnyProp
}

private AnyModel(final Registry registry, final Declarer declarer, final AnyElement element) {
super(registry, declarer, element.nullable(), null, null, null);
super(registry, declarer, element.nullable(), null, null, null, null);
this.types = getMemberTypes(element.types());
validateTypeBinding();
}
Expand Down Expand Up @@ -472,10 +472,10 @@ void toAnnotationAttributes(final AttributeMap attributes, final Member owner) {
for (int i = 0, i$ = types.size(); i < i$; ++i) { // [RA]
final Member type = types.get(i);
if (type instanceof ArrayModel) {
values.add("@" + t.class.getName() + "(arrays = " + ((ArrayModel)type).classType().getCanonicalName() + ".class)");
values.add("@" + t.class.getName() + "(arrays = " + ((ArrayModel)type).classType().canonicalName + ".class)");
}
else if (type instanceof ObjectModel) {
values.add("@" + t.class.getName() + "(objects = " + ((ObjectModel)type).classType().getCanonicalName() + ".class)");
values.add("@" + t.class.getName() + "(objects = " + ((ObjectModel)type).classType().canonicalName + ".class)");
}
else if (type instanceof BooleanModel || type instanceof NumberModel || type instanceof StringModel) {
final Model model = (Model)type;
Expand Down
6 changes: 3 additions & 3 deletions generator/src/main/java/org/jsonx/ArrayModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ private static Integer parseIterate(final Integer minIterate) {
}

private ArrayModel(final Registry registry, final Declarer declarer, final Schema.Array xsb, final IdentityHashMap<$AnyType<?>,$FieldBinding> xsbToBinding) {
super(registry, declarer, registry.getType(Registry.Kind.ANNOTATION, registry.packageName, registry.classBasePath + JsdUtil.flipName(xsb.getName$().text())), xsb.getDoc$(), xsb.getName$().text());
super(registry, declarer, registry.getType(Registry.Kind.ANNOTATION, registry.packageName, registry.classBasePath + JsdUtil.flipName(xsb.getName$().text())), xsb.getDoc$(), xsb.getName$().text(), null);
this.members = parseMembers(registry, this, xsb, xsbToBinding);
final MinIterate$ minIterate$ = xsb.getMinIterate$();
this.minIterate = parseIterate(minIterate$.text());
Expand Down Expand Up @@ -422,7 +422,7 @@ private ArrayModel(final Registry registry, final Declarer declarer, final Id id
}

private ArrayModel(final Registry registry, final Declarer declarer, final ArrayElement arrayElement, final Map<Integer,Annotation> idToElement, final String declaringTypeName) {
super(registry, declarer, arrayElement.nullable(), null, null, null);
super(registry, declarer, arrayElement.nullable(), null, null, null, null);
if (arrayElement.type() != ArrayType.class)
throw new IllegalArgumentException("This constructor is only for elementIds");

Expand Down Expand Up @@ -563,7 +563,7 @@ private void renderAnnotations(final AttributeMap attributes, final List<? super
void toAnnotationAttributes(final AttributeMap attributes, final Member owner) {
super.toAnnotationAttributes(attributes, owner);
if (classType() != null) {
attributes.put("type", classType().getCanonicalName() + ".class");
attributes.put("type", classType().canonicalName + ".class");
writeIterateClauses(attributes);
}
else {
Expand Down
3 changes: 2 additions & 1 deletion generator/src/main/java/org/jsonx/Bind.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
import java.util.Optional;

import org.jsonx.www.binding_0_5.xL1gluGCXAA.$CodecTypeFieldBinding;
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$TypeFieldBinding;
import org.libj.lang.Identifiers;
import org.libj.lang.ObjectUtil;
import org.libj.util.ArrayUtil;

final class Bind {
static class Type {
static Type from(final Registry registry, final $CodecTypeFieldBinding.Type$ type, final $CodecTypeFieldBinding.Decode$ decode, final $CodecTypeFieldBinding.Encode$ encode) {
static Type from(final Registry registry, final $TypeFieldBinding.Type$ type, final $CodecTypeFieldBinding.Decode$ decode, final $CodecTypeFieldBinding.Encode$ encode) {
return type == null && decode == null && encode == null ? null : new Type(registry, type == null ? null : type.text(), decode == null ? null : decode.text(), encode == null ? null : encode.text());
}

Expand Down
43 changes: 26 additions & 17 deletions generator/src/main/java/org/jsonx/ClassSpec.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,49 +40,52 @@ enum Scope {
final Referrer<?> referrer;
private final Registry registry;
private final Registry.Type type;
private final Bind.Type typeBinding;

ClassSpec(final Referrer<?> referrer) {
this.referrer = referrer;
this.registry = referrer.registry;
this.type = referrer.classType();
this.typeBinding = referrer.typeBinding;
}

ClassSpec(final ClassSpec parent, final Registry.Type type) {
this.referrer = null;
this.registry = parent.registry;
this.type = type;
this.typeBinding = null;
}

String getDoc() {
return referrer != null && referrer.doc != null ? "/** " + referrer.doc.trim() + " **/" : null;
}

StringBuilder getAnnotation() {
StringBuilder builder = null;
if (type.getKind() == Registry.Kind.ANNOTATION) {
builder = new StringBuilder();
builder.append('@').append(Retention.class.getName()).append('(').append(RetentionPolicy.class.getName()).append('.').append(RetentionPolicy.RUNTIME).append(')');
StringBuilder b = null;
if (type.kind == Registry.Kind.ANNOTATION) {
b = new StringBuilder();
b.append('@').append(Retention.class.getName()).append('(').append(RetentionPolicy.class.getName()).append('.').append(RetentionPolicy.RUNTIME).append(')');
}

if (referrer == null || referrer.getClassAnnotation() == null || referrer.getClassAnnotation().size() == 0)
return builder;
return b;

if (builder == null)
builder = new StringBuilder();
if (b == null)
b = new StringBuilder();

final ArrayList<AnnotationType> annotations = referrer.getClassAnnotation();
for (int i = 0, i$ = annotations.size(); i < i$; ++i) { // [RA]
if (builder.length() > 0)
builder.append('\n');
if (b.length() > 0)
b.append('\n');

builder.append(annotations.get(i));
b.append(annotations.get(i));
}

return builder.length() == 0 ? null : builder;
return b.length() == 0 ? null : b;
}

void add(final ClassSpec classSpec) {
nameToClassSpec.put(classSpec.type.getName(), classSpec);
nameToClassSpec.put(classSpec.type.name, classSpec);
}

private String toString(final ClassSpec parent) {
Expand All @@ -93,13 +96,19 @@ private String toString(final ClassSpec parent) {
if (parent != null)
b.append("static ");

b.append(type.getKind()).append(' ').append(type.getSimpleName());
if (type.getKind() == Registry.Kind.CLASS && referrer != null) {
b.append(type.kind).append(' ').append(type.simpleName);
if (type.kind == Registry.Kind.CLASS && referrer != null) {
final Type superType = type.getSuperType();
if (superType != null)
b.append(" extends ").append(superType.getCanonicalName());
else
if (superType != null) {
b.append(" extends ").append(superType.canonicalName);
if (typeBinding != null)
b.append(" implements ").append(typeBinding.type.canonicalName);
}
else {
b.append(" implements ").append(JxObject.class.getCanonicalName());
if (typeBinding != null)
b.append(", ").append(typeBinding.type.canonicalName);
}
}

b.append(" {");
Expand Down
2 changes: 1 addition & 1 deletion generator/src/main/java/org/jsonx/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public static String jsonToXml(final URL url) throws DecodeException, IOExceptio
*/
public static String xmlToJson(final URL url) throws IOException, SAXException {
final SchemaElement[] schemaElements = Generator.parse(settings, url);
for (final SchemaElement schemaElement : schemaElements)
for (final SchemaElement schemaElement : schemaElements) // [A]
if (schemaElement.getLocation() == url)
return JSON.toString(schemaElement.toJson(), 2);

Expand Down
2 changes: 1 addition & 1 deletion generator/src/main/java/org/jsonx/Id.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static Id hashed(final String designation, final Object ... variables) {
}

static Id named(final Registry.Type type) {
return new Id(type != null ? JsdUtil.flipName(type.getName()) : Strings.getRandomAlphaNumeric(6));
return new Id(type != null ? JsdUtil.flipName(type.name) : Strings.getRandomAlphaNumeric(6));
}

static Id named(final Class<?> type) {
Expand Down
18 changes: 10 additions & 8 deletions generator/src/main/java/org/jsonx/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,13 @@ final Class<?> validateTypeBinding() {
final boolean hasDecodeBinding = typeBinding != null && typeBinding.decode != null;
if (typeBinding.type.isPrimitive && !typeBinding.type.isArray && !hasDecodeBinding) {
if (use.set == Use.OPTIONAL)
throw new ValidationException("\"" + fullyQualifiedDisplayName(declarer) + "\" cannot declare " + nameForException() + " (" + elementName() + ") with primitive type \"" + typeBinding.type.getCompositeName() + "\" and use=optional: Either change to an Object type, or declare a \"decode\" binding to handle null values.");
throw new ValidationException("\"" + fullyQualifiedDisplayName(declarer) + "\" cannot declare " + nameForException() + " (" + elementName() + ") with primitive type \"" + typeBinding.type.compositeName + "\" and use=optional: Either change to an Object type, or declare a \"decode\" binding to handle null values.");

if (!(declarer instanceof SchemaElement) && nullable.get == null && !hasDecodeBinding)
throw new ValidationException("\"" + fullyQualifiedDisplayName(declarer) + "\" cannot declare " + nameForException() + " (" + elementName() + ") with primitive type \"" + typeBinding.type.getCompositeName() + "\" and nullable=true: Either change to an Object type, or declare a \"decode\" binding to handle null values.");
throw new ValidationException("\"" + fullyQualifiedDisplayName(declarer) + "\" cannot declare " + nameForException() + " (" + elementName() + ") with primitive type \"" + typeBinding.type.compositeName + "\" and nullable=true: Either change to an Object type, or declare a \"decode\" binding to handle null values.");

if (declarer instanceof AnyModel)
throw new ValidationException("\"" + fullyQualifiedDisplayName(declarer) + "\" cannot declare " + nameForException() + " (" + elementName() + ") with primitive type \"" + typeBinding.type.getCompositeName() + "\" as an \"any\" property type: Either change to an Object type, or change to a property type other than \"any\".");
throw new ValidationException("\"" + fullyQualifiedDisplayName(declarer) + "\" cannot declare " + nameForException() + " (" + elementName() + ") with primitive type \"" + typeBinding.type.compositeName + "\" as an \"any\" property type: Either change to an Object type, or change to a property type other than \"any\".");
}

// Check that we have: ? super CharSequence -> decode -> [type] -> encode -> ? extends CharSequence
Expand Down Expand Up @@ -256,12 +256,12 @@ final Class<?> validateTypeBinding() {
if (cls != null) {
if (decodeMethod != null) {
if (!Classes.isAssignableFrom(cls, JsdUtil.getReturnType(decodeMethod))) {
error = "The return type of \"decode\" method \"" + decodeMethod + "\" in " + JsdUtil.flipName(id().toString()) + " is not assignable to: " + typeBinding.type.getName();
error = "The return type of \"decode\" method \"" + decodeMethod + "\" in " + JsdUtil.flipName(id().toString()) + " is not assignable to: " + typeBinding.type.name;
}
}
else if (encodeMethod == null) {
if (!Classes.isAssignableFrom(defaultClass(), cls) && !Classes.isAssignableFrom(CharSequence.class, cls)) {
error = "The type binding \"" + typeBinding.type.getName() + "\" in " + JsdUtil.flipName(id().toString()) + " is not \"encode\" compatible with " + defaultClass().getName() + " or " + CharSequence.class.getName();
error = "The type binding \"" + typeBinding.type.name + "\" in " + JsdUtil.flipName(id().toString()) + " is not \"encode\" compatible with " + defaultClass().getName() + " or " + CharSequence.class.getName();
}
}
}
Expand Down Expand Up @@ -386,6 +386,8 @@ final String toField(final Registry.Type classType, final Member override, final
b.append(annotationType).append('\n');

final String arrayOverrideSafeTypeName = override != null && isArrayOverride(override) ? override.type().toCanonicalString() : typeName;
if ("java.util.EventListener".equals(arrayOverrideSafeTypeName))
registry.getOptionalType(type().asGeneric(null));

b.append("public ").append(arrayOverrideSafeTypeName).append(" get").append(classCase).append("() {\n return ");
if (override == null)
Expand All @@ -403,7 +405,7 @@ else if (isArrayOverride(override))
if (doc != null)
b.append(doc).append('\n');

final String classSimpleName = classType.getSimpleName();
final String classSimpleName = classType.simpleName;
b.append("public ").append(setBuilder ? classSimpleName : "void").append(" set").append(classCase).append("(final ").append(typeName).append(' ').append(instanceCase).append(") {\n ");
if (override != null)
b.append("super.set").append(classCase).append('(').append(instanceCase).append(')');
Expand All @@ -412,7 +414,7 @@ else if (isArrayOverride(override))
b.append(";\n");
if (setBuilder) {
b.append(" return ");
if (!declarer.classType().getSimpleName().equals(classSimpleName))
if (!declarer.classType().simpleName.equals(classSimpleName))
b.append('(').append(classSimpleName).append(')');

b.append("this;\n");
Expand Down Expand Up @@ -465,7 +467,7 @@ Registry.Type typeBinding() {
return typeBinding == null ? null : typeBinding.type;
}

final Registry.Type type() {
Registry.Type type() {
final Registry.Type typeBinding = typeBinding();
return typeBinding != null ? typeBinding : typeDefault(!(declarer instanceof ArrayModel) && use.get == null && Boolean.FALSE.equals(nullable.get)); // FIXME: Note that this line says: "if it's a list, it's always an object member" What about primitive arrays?!
}
Expand Down
7 changes: 3 additions & 4 deletions generator/src/main/java/org/jsonx/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,16 @@ XmlElement toXml(final Element owner, final String packageName, final JsonPath.C

@Override
PropertyMap<Object> toJson(final Element owner, final String packageName, final JsonPath.Cursor cursor, final PropertyMap<AttributeMap> pathToBinding) {
final PropertyMap<Object> properties = new PropertyMap<>();
properties.put("@", elementName());

final AttributeMap attributes = toSchemaAttributes(owner, packageName, true);
cursor.pushName((String)attributes.get("name"));

final AttributeMap bindingAttributes = Bind.toBindingAttributes(elementName(), owner, typeBinding, fieldBinding, attributes, true);
if (bindingAttributes != null)
pathToBinding.put(cursor.toString(), bindingAttributes);

attributes.remove(nameName());

final PropertyMap<Object> properties = new PropertyMap<>();
properties.put("@", elementName());
properties.putAll(attributes);
return properties;
}
Expand Down
4 changes: 2 additions & 2 deletions generator/src/main/java/org/jsonx/NumberModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import java.util.IdentityHashMap;

import org.jaxsb.runtime.Bindings;
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$CodecTypeFieldBinding;
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$FieldBinding;
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$FieldIdentifier;
import org.jsonx.www.binding_0_5.xL1gluGCXAA.$CodecTypeFieldBinding;
import org.jsonx.www.schema_0_5.xL0gluGCXAA.$Array;
import org.jsonx.www.schema_0_5.xL0gluGCXAA.$ArrayMember;
import org.jsonx.www.schema_0_5.xL0gluGCXAA.$Documented;
Expand Down Expand Up @@ -278,7 +278,7 @@ String isValid(final Bind.Type typeBinding) {

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

return null;
}
Expand Down
Loading

0 comments on commit e36735a

Please sign in to comment.