1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.databind.codegen.typeinfo;
7   
8   import com.squareup.javapoet.AnnotationSpec;
9   import com.squareup.javapoet.ClassName;
10  import com.squareup.javapoet.FieldSpec;
11  import com.squareup.javapoet.TypeName;
12  import com.squareup.javapoet.TypeSpec;
13  
14  import java.util.Set;
15  
16  import dev.metaschema.core.datatype.IDataTypeAdapter;
17  import dev.metaschema.core.model.IFieldDefinition;
18  import dev.metaschema.core.model.IFieldInstance;
19  import dev.metaschema.core.model.IFieldInstanceAbsolute;
20  import dev.metaschema.core.model.IModelDefinition;
21  import dev.metaschema.core.util.ObjectUtils;
22  import dev.metaschema.databind.codegen.impl.AnnotationGenerator;
23  import dev.metaschema.databind.codegen.typeinfo.def.IAssemblyDefinitionTypeInfo;
24  import dev.metaschema.databind.model.annotations.BoundField;
25  import edu.umd.cs.findbugs.annotations.NonNull;
26  
27  public class FieldInstanceTypeInfoImpl
28      extends AbstractNamedModelInstanceTypeInfo<IFieldInstanceAbsolute>
29      implements IFieldInstanceTypeInfo {
30  
31    /**
32     * Constructs a new type information object for a field instance.
33     *
34     * @param instance
35     *          the field instance
36     * @param parentDefinition
37     *          the type information for the parent assembly definition containing
38     *          this instance
39     */
40    public FieldInstanceTypeInfoImpl(
41        @NonNull IFieldInstanceAbsolute instance,
42        @NonNull IAssemblyDefinitionTypeInfo parentDefinition) {
43      super(instance, parentDefinition);
44    }
45  
46    @Override
47    public TypeName getJavaItemType() {
48      TypeName retval;
49      IFieldInstance fieldInstance = getInstance();
50      if (fieldInstance.getDefinition().hasChildren()) {
51        retval = super.getJavaItemType();
52      } else {
53        IDataTypeAdapter<?> dataType = fieldInstance.getDefinition().getJavaTypeAdapter();
54        // this is a simple value
55        retval = ObjectUtils.notNull(ClassName.get(dataType.getJavaClass()));
56      }
57      return retval;
58    }
59  
60    @Override
61    protected AnnotationSpec.Builder newBindingAnnotation() {
62      return ObjectUtils.notNull(AnnotationSpec.builder(BoundField.class));
63    }
64  
65    @SuppressWarnings("checkstyle:methodlength")
66    @Override
67    public Set<IModelDefinition> buildBindingAnnotation(
68        TypeSpec.Builder typeBuilder,
69        FieldSpec.Builder fieldBuilder,
70        AnnotationSpec.Builder annotation) {
71      // first build the core attributes
72      final Set<IModelDefinition> retval = super.buildBindingAnnotation(typeBuilder, fieldBuilder, annotation);
73  
74      IFieldInstance instance = getInstance();
75  
76      // next build the field-specific attributes
77      if (IFieldInstance.DEFAULT_FIELD_IN_XML_WRAPPED != instance.isInXmlWrapped()) {
78        annotation.addMember("inXmlWrapped", "$L", instance.isInXmlWrapped());
79      }
80  
81      IFieldDefinition definition = instance.getDefinition();
82      IDataTypeAdapter<?> adapter = instance.getDefinition().getJavaTypeAdapter();
83  
84      Object defaultValue = instance.getDefaultValue();
85      if (defaultValue != null) {
86        annotation.addMember("defaultValue", "$S", adapter.asString(defaultValue));
87      }
88  
89      // handle the field value related info
90      if (!definition.hasChildren()) {
91        // this is a simple field, without flags
92        // Always add typeAdapter so the reader knows to treat this as a simple value
93        annotation.addMember("typeAdapter", "$T.class", adapter.getClass());
94        AnnotationGenerator.buildValueConstraints(annotation, definition);
95      }
96      return retval;
97    }
98  }