Subversion Repositories bacoAlunos

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1878 jmachado 1
package com.owlike.genson.reflect;
2
 
3
import java.util.ArrayList;
4
import java.util.Arrays;
5
import java.util.Collections;
6
import java.util.Comparator;
7
import java.util.LinkedHashMap;
8
import java.util.List;
9
import java.util.Map;
10
 
11
import com.owlike.genson.*;
12
import com.owlike.genson.reflect.BeanCreator.BeanCreatorProperty;
13
import com.owlike.genson.stream.ObjectReader;
14
import com.owlike.genson.stream.ObjectWriter;
15
 
16
/**
17
 * BeanDescriptors are used to serialize/deserialize objects based on their fields, methods and
18
 * constructors. By default it is supposed to work on JavaBeans, however it can be configured and
19
 * extended to support different kind of objects.
20
 * <p/>
21
 * In most cases BeanDescriptors should not be used directly as it is used internally to support
22
 * objects not handled by the default Converters. The most frequent case when you will use directly
23
 * a BeanDescriptor is when you want to deserialize into an existing instance. Here is an example :
24
 * <p/>
25
 * <pre>
26
 * Genson genson = new Genson();
27
 * BeanDescriptorProvider provider = genson.getBeanDescriptorProvider();
28
 * BeanDescriptor&lt;MyClass&gt; descriptor = provider.provide(MyClass.class, genson);
29
 *
30
 * MyClass existingInstance = descriptor.deserialize(existingInstance, new JsonReader(&quot;{}&quot;),
31
 *              new Context(genson));
32
 * </pre>
33
 *
34
 * @param <T> type that this BeanDescriptor can serialize and deserialize.
35
 * @author eugen
36
 * @see BeanDescriptorProvider
37
 */
38
public class BeanDescriptor<T> implements Converter<T> {
39
  final Class<?> fromDeclaringClass;
40
  final Class<T> ofClass;
41
  final Map<String, PropertyMutator> mutableProperties;
42
  final List<PropertyAccessor> accessibleProperties;
43
  final boolean failOnMissingProperty;
44
 
45
  final BeanCreator creator;
46
  private final boolean _noArgCtr;
47
 
48
  private static final 5+0%2Fdocs%2Fapi+Object">Object MISSING = new 5+0%2Fdocs%2Fapi+Object">Object();
49
  // Used as a cache so we just copy it instead of recreating and assigning the default values
50
  private 5+0%2Fdocs%2Fapi+Object">Object[] globalCreatorArgs;
51
 
52
  private final static Comparator<BeanProperty> _readablePropsComparator = new Comparator<BeanProperty>() {
53
    public int compare(BeanProperty o1, BeanProperty o2) {
54
      return o1.name.compareToIgnoreCase(o2.name);
55
    }
56
  };
57
 
58
  public 1.5.0/docs/api/java/beans/BeanDescriptor.html">BeanDescriptor(Class<T> forClass, Class<?> fromDeclaringClass,
59
                        List<PropertyAccessor> readableBps,
60
                        Map<String, PropertyMutator> writableBps, BeanCreator creator,
61
                        boolean failOnMissingProperty) {
62
    this.ofClass = forClass;
63
    this.fromDeclaringClass = fromDeclaringClass;
64
    this.creator = creator;
65
    this.failOnMissingProperty = failOnMissingProperty;
66
    mutableProperties = writableBps;
67
 
68
    1.5.0/docs/api/java/util/Collections.html">Collections.sort(readableBps, _readablePropsComparator);
69
 
70
    accessibleProperties = 1.5.0/docs/api/java/util/Collections.html">Collections.unmodifiableList(readableBps);
71
    if (this.creator != null) {
72
      _noArgCtr = this.creator.parameters.size() == 0;
73
      globalCreatorArgs = new 5+0%2Fdocs%2Fapi+Object">Object[creator.parameters.size()];
74
      1.5.0/docs/api/java/util/Arrays.html">Arrays.fill(globalCreatorArgs, MISSING);
75
    } else {
76
      _noArgCtr = false;
77
    }
78
  }
79
 
80
  public boolean isReadable() {
81
    return !accessibleProperties.isEmpty();
82
  }
83
 
84
  public boolean isWritable() {
85
    return creator != null;
86
  }
87
 
88
  public void serialize(T obj, ObjectWriter writer, 5+0%2Fdocs%2Fapi+Context">Context ctx) {
89
    writer.beginObject();
90
    RuntimePropertyFilter runtimePropertyFilter = ctx.genson.runtimePropertyFilter();
91
    for (PropertyAccessor accessor : accessibleProperties) {
92
      if (runtimePropertyFilter.shouldInclude(accessor, ctx)) accessor.serialize(obj, writer, ctx);
93
    }
94
    writer.endObject();
95
  }
96
 
97
  public T deserialize(ObjectReader reader, 5+0%2Fdocs%2Fapi+Context">Context ctx) {
98
    T bean = null;
99
    // optimization for default ctr
100
    if (_noArgCtr) {
101
      bean = ofClass.cast(creator.create());
102
      deserialize(bean, reader, ctx);
103
    } else {
104
      if (creator == null)
105
        throw new JsonBindingException("No constructor has been found for type "
106
          + ofClass);
107
      bean = _deserWithCtrArgs(reader, ctx);
108
    }
109
    return bean;
110
  }
111
 
112
  public void deserialize(T into, ObjectReader reader, 5+0%2Fdocs%2Fapi+Context">Context ctx) {
113
    reader.beginObject();
114
    RuntimePropertyFilter runtimePropertyFilter = ctx.genson.runtimePropertyFilter();
115
    for (; reader.hasNext(); ) {
116
      reader.next();
117
      1.5.0/docs/api/java/lang/String.html">String propName = reader.name();
118
      PropertyMutator mutator = mutableProperties.get(propName);
119
      if (mutator != null) {
120
        if (runtimePropertyFilter.shouldInclude(mutator, ctx)) {
121
          mutator.deserialize(into, reader, ctx);
122
        } else {
123
          reader.skipValue();
124
        }
125
      } else if (failOnMissingProperty) throw missingPropertyException(propName);
126
      else reader.skipValue();
127
    }
128
    reader.endObject();
129
  }
130
 
131
 
132
  protected T _deserWithCtrArgs(ObjectReader reader, 5+0%2Fdocs%2Fapi+Context">Context ctx) {
133
    List<String> names = new ArrayList<String>();
134
    List<Object> values = new ArrayList<Object>();
135
    RuntimePropertyFilter runtimePropertyFilter = ctx.genson.runtimePropertyFilter();
136
 
137
    reader.beginObject();
138
    for (; reader.hasNext(); ) {
139
      reader.next();
140
      1.5.0/docs/api/java/lang/String.html">String propName = reader.name();
141
      PropertyMutator muta = mutableProperties.get(propName);
142
 
143
      if (muta != null) {
144
        if (runtimePropertyFilter.shouldInclude(muta, ctx)) {
145
          5+0%2Fdocs%2Fapi+Object">Object param = muta.deserialize(reader, ctx);
146
          names.add(propName);
147
          values.add(param);
148
        } else {
149
          reader.skipValue();
150
        }
151
      } else if (failOnMissingProperty) throw missingPropertyException(propName);
152
      else reader.skipValue();
153
    }
154
 
155
    int size = names.size();
156
    int foundCtrParameters = 0;
157
    5+0%2Fdocs%2Fapi+Object">Object[] creatorArgs = globalCreatorArgs.clone();
158
    1.5.0/docs/api/java/lang/String.html">String[] newNames = new 1.5.0/docs/api/java/lang/String.html">String[size];
159
    5+0%2Fdocs%2Fapi+Object">Object[] newValues = new 5+0%2Fdocs%2Fapi+Object">Object[size];
160
 
161
    for (int i = 0, j = 0; i < size; i++) {
162
      BeanCreatorProperty mp = creator.paramsAndAliases.get(names.get(i));
163
      if (mp != null) {
164
        creatorArgs[mp.index] = values.get(i);
165
        foundCtrParameters++;
166
      } else {
167
        newNames[j] = names.get(i);
168
        newValues[j] = values.get(i);
169
        j++;
170
      }
171
    }
172
 
173
    if (foundCtrParameters < creator.parameters.size()) updateWithDefaultValues(creatorArgs, ctx.genson);
174
 
175
    T bean = ofClass.cast(creator.create(creatorArgs));
176
    for (int i = 0; i < size; i++) {
177
      PropertyMutator property = mutableProperties.get(newNames[i]);
178
      if (property != null) property.mutate(bean, newValues[i]);
179
    }
180
    reader.endObject();
181
    return bean;
182
  }
183
 
184
  private void updateWithDefaultValues(5+0%2Fdocs%2Fapi+Object">Object[] creatorArgs, Genson genson) {
185
    for (int i = 0; i < creatorArgs.length; i++) {
186
      if (creatorArgs[i] == MISSING) {
187
        for (BeanCreatorProperty property : creator.parameters.values()) {
188
          if (property.index == i) {
189
            creatorArgs[i] = genson.defaultValue(property.getRawClass());
190
            break;
191
          }
192
        }
193
      }
194
    }
195
  }
196
 
197
  public Class<T> getOfClass() {
198
    return ofClass;
199
  }
200
 
201
  private JsonBindingException missingPropertyException(1.5.0/docs/api/java/lang/String.html">String name) {
202
   return new JsonBindingException("No matching property in " + getOfClass() + " for key " + name);
203
  }
204
}