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 package gov.nist.secauto.metaschema.databind.model;
28
29 import gov.nist.secauto.metaschema.core.model.IModule;
30 import gov.nist.secauto.metaschema.core.model.ModuleScopeEnum;
31 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
32 import gov.nist.secauto.metaschema.databind.IBindingContext;
33 import gov.nist.secauto.metaschema.databind.io.BindingException;
34
35 import java.lang.reflect.Constructor;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.util.Locale;
39
40 import edu.umd.cs.findbugs.annotations.NonNull;
41
42 abstract class AbstractClassBinding implements IClassBinding {
43
44
45
46 @NonNull
47 private final IBindingContext bindingContext;
48 @NonNull
49 private final Class<?> clazz;
50 private final Method beforeDeserializeMethod;
51 private final Method afterDeserializeMethod;
52
53 private IModule module;
54
55
56
57
58
59
60
61
62
63 public AbstractClassBinding(@NonNull Class<?> clazz, @NonNull IBindingContext bindingContext) {
64 this.bindingContext = ObjectUtils.requireNonNull(bindingContext, "bindingContext");
65 this.clazz = ObjectUtils.requireNonNull(clazz, "clazz");
66 this.beforeDeserializeMethod = ClassIntrospector.getMatchingMethod(clazz, "beforeDeserialize", Object.class);
67 this.afterDeserializeMethod = ClassIntrospector.getMatchingMethod(clazz, "afterDeserialize", Object.class);
68 }
69
70 @Override
71 public boolean isInline() {
72 return getBoundClass().getEnclosingClass() != null;
73 }
74
75 @Override
76 public Class<?> getBoundClass() {
77 return clazz;
78 }
79
80 @Override
81 public IBindingContext getBindingContext() {
82 return bindingContext;
83 }
84
85 @Override
86 public String getUseName() {
87
88 return null;
89 }
90
91 @SuppressWarnings("null")
92 @Override
93 public String toCoordinates() {
94 return String.format("%s IClassBinding(%s): %s", getModelType().name().toLowerCase(Locale.ROOT), getName(),
95 getBoundClass().getName());
96 }
97
98 @Override
99 public @NonNull ModuleScopeEnum getModuleScope() {
100
101 return ModuleScopeEnum.INHERITED;
102 }
103
104 protected abstract Class<? extends IModule> getModuleClass();
105
106 @SuppressWarnings("null")
107 @NonNull
108 protected IModule initModule() {
109 synchronized (this) {
110 if (module == null) {
111 Class<? extends IModule> metaschemaClass = getModuleClass();
112 module = getBindingContext().getModuleByClass(metaschemaClass);
113 }
114 return module;
115 }
116 }
117
118 @Override
119 public IModule getContainingModule() {
120 return initModule();
121 }
122
123
124
125
126
127
128
129
130
131
132 @Override
133 @NonNull
134 public <CLASS> CLASS newInstance() throws BindingException {
135 Class<?> clazz = getBoundClass();
136 try {
137 @SuppressWarnings("unchecked") Constructor<CLASS> constructor
138 = (Constructor<CLASS>) clazz.getDeclaredConstructor();
139 return ObjectUtils.notNull(constructor.newInstance());
140 } catch (NoSuchMethodException ex) {
141 String msg = String.format("Class '%s' does not have a required no-arg constructor.", clazz.getName());
142 throw new BindingException(msg, ex);
143 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
144 | InvocationTargetException ex) {
145 throw new BindingException(ex);
146 }
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 @Override
165 public void callBeforeDeserialize(Object targetObject, Object parentObject) throws BindingException {
166 if (beforeDeserializeMethod != null) {
167 try {
168 beforeDeserializeMethod.invoke(targetObject, parentObject);
169 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
170 throw new BindingException(ex);
171 }
172 }
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 @Override
191 public void callAfterDeserialize(Object targetObject, Object parentObject) throws BindingException {
192 if (afterDeserializeMethod != null) {
193 try {
194 afterDeserializeMethod.invoke(targetObject, parentObject);
195 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
196 throw new BindingException(ex);
197 }
198 }
199 }
200
201 @Override
202 public Object copyBoundObject(Object item, Object parentInstance) throws BindingException {
203 Object instance = newInstance();
204
205 callBeforeDeserialize(instance, parentInstance);
206
207 copyBoundObjectInternal(item, instance);
208
209 callAfterDeserialize(instance, parentInstance);
210
211 return instance;
212 }
213
214 protected void copyBoundObjectInternal(@NonNull Object fromInstance, @NonNull Object toInstance)
215 throws BindingException {
216 for (IBoundFlagInstance property : getFlagInstances()) {
217 property.copyBoundObject(fromInstance, toInstance);
218 }
219 }
220 }