Bukkit-API  1.7.9-R0.2
The inofficial Bukkit-API
ConfigurationSerialization.java
1 package org.bukkit.configuration.serialization;
2 
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.Modifier;
7 import java.util.HashMap;
8 import java.util.Map;
9 import java.util.logging.Level;
10 import java.util.logging.Logger;
11 
12 import org.apache.commons.lang.Validate;
13 import org.bukkit.Color;
18 import org.bukkit.util.BlockVector;
19 import org.bukkit.util.Vector;
20 
21 /**
22  * Utility class for storing and retrieving classes for {@link Configuration}.
23  */
25  public static final String SERIALIZED_TYPE_KEY = "==";
26  private final Class<? extends ConfigurationSerializable> clazz;
27  private static Map<String, Class<? extends ConfigurationSerializable>> aliases = new HashMap<String, Class<? extends ConfigurationSerializable>>();
28 
29  static {
30  registerClass(Vector.class);
32  registerClass(ItemStack.class);
33  registerClass(Color.class);
36  }
37 
38  protected ConfigurationSerialization(Class<? extends ConfigurationSerializable> clazz) {
39  this.clazz = clazz;
40  }
41 
42  protected Method getMethod(String name, boolean isStatic) {
43  try {
44  Method method = clazz.getDeclaredMethod(name, Map.class);
45 
46  if (!ConfigurationSerializable.class.isAssignableFrom(method.getReturnType())) {
47  return null;
48  }
49  if (Modifier.isStatic(method.getModifiers()) != isStatic) {
50  return null;
51  }
52 
53  return method;
54  } catch (NoSuchMethodException ex) {
55  return null;
56  } catch (SecurityException ex) {
57  return null;
58  }
59  }
60 
61  protected Constructor<? extends ConfigurationSerializable> getConstructor() {
62  try {
63  return clazz.getConstructor(Map.class);
64  } catch (NoSuchMethodException ex) {
65  return null;
66  } catch (SecurityException ex) {
67  return null;
68  }
69  }
70 
71  protected ConfigurationSerializable deserializeViaMethod(Method method, Map<String, ?> args) {
72  try {
73  ConfigurationSerializable result = (ConfigurationSerializable) method.invoke(null, args);
74 
75  if (result == null) {
76  Logger.getLogger(ConfigurationSerialization.class.getName()).log(Level.SEVERE, "Could not call method '" + method.toString() + "' of " + clazz + " for deserialization: method returned null");
77  } else {
78  return result;
79  }
80  } catch (Throwable ex) {
81  Logger.getLogger(ConfigurationSerialization.class.getName()).log(
82  Level.SEVERE,
83  "Could not call method '" + method.toString() + "' of " + clazz + " for deserialization",
84  ex instanceof InvocationTargetException ? ex.getCause() : ex);
85  }
86 
87  return null;
88  }
89 
90  protected ConfigurationSerializable deserializeViaCtor(Constructor<? extends ConfigurationSerializable> ctor, Map<String, ?> args) {
91  try {
92  return ctor.newInstance(args);
93  } catch (Throwable ex) {
94  Logger.getLogger(ConfigurationSerialization.class.getName()).log(
95  Level.SEVERE,
96  "Could not call constructor '" + ctor.toString() + "' of " + clazz + " for deserialization",
97  ex instanceof InvocationTargetException ? ex.getCause() : ex);
98  }
99 
100  return null;
101  }
102 
103  public ConfigurationSerializable deserialize(Map<String, ?> args) {
104  Validate.notNull(args, "Args must not be null");
105 
106  ConfigurationSerializable result = null;
107  Method method = null;
108 
109  if (result == null) {
110  method = getMethod("deserialize", true);
111 
112  if (method != null) {
113  result = deserializeViaMethod(method, args);
114  }
115  }
116 
117  if (result == null) {
118  method = getMethod("valueOf", true);
119 
120  if (method != null) {
121  result = deserializeViaMethod(method, args);
122  }
123  }
124 
125  if (result == null) {
126  Constructor<? extends ConfigurationSerializable> constructor = getConstructor();
127 
128  if (constructor != null) {
129  result = deserializeViaCtor(constructor, args);
130  }
131  }
132 
133  return result;
134  }
135 
136  /**
137  * Attempts to deserialize the given arguments into a new instance of the
138  * given class.
139  * <p>
140  * The class must implement {@link ConfigurationSerializable}, including
141  * the extra methods as specified in the javadoc of
142  * ConfigurationSerializable.
143  * <p>
144  * If a new instance could not be made, an example being the class not
145  * fully implementing the interface, null will be returned.
146  *
147  * @param args Arguments for deserialization
148  * @param clazz Class to deserialize into
149  * @return New instance of the specified class
150  */
151  public static ConfigurationSerializable deserializeObject(Map<String, ?> args, Class<? extends ConfigurationSerializable> clazz) {
152  return new ConfigurationSerialization(clazz).deserialize(args);
153  }
154 
155  /**
156  * Attempts to deserialize the given arguments into a new instance of the
157  * given class.
158  * <p>
159  * The class must implement {@link ConfigurationSerializable}, including
160  * the extra methods as specified in the javadoc of
161  * ConfigurationSerializable.
162  * <p>
163  * If a new instance could not be made, an example being the class not
164  * fully implementing the interface, null will be returned.
165  *
166  * @param args Arguments for deserialization
167  * @return New instance of the specified class
168  */
169  public static ConfigurationSerializable deserializeObject(Map<String, ?> args) {
170  Class<? extends ConfigurationSerializable> clazz = null;
171 
172  if (args.containsKey(SERIALIZED_TYPE_KEY)) {
173  try {
174  String alias = (String) args.get(SERIALIZED_TYPE_KEY);
175 
176  if (alias == null) {
177  throw new IllegalArgumentException("Cannot have null alias");
178  }
179  clazz = getClassByAlias(alias);
180  if (clazz == null) {
181  throw new IllegalArgumentException("Specified class does not exist ('" + alias + "')");
182  }
183  } catch (ClassCastException ex) {
184  ex.fillInStackTrace();
185  throw ex;
186  }
187  } else {
188  throw new IllegalArgumentException("Args doesn't contain type key ('" + SERIALIZED_TYPE_KEY + "')");
189  }
190 
191  return new ConfigurationSerialization(clazz).deserialize(args);
192  }
193 
194  /**
195  * Registers the given {@link ConfigurationSerializable} class by its
196  * alias
197  *
198  * @param clazz Class to register
199  */
200  public static void registerClass(Class<? extends ConfigurationSerializable> clazz) {
201  DelegateDeserialization delegate = clazz.getAnnotation(DelegateDeserialization.class);
202 
203  if (delegate == null) {
204  registerClass(clazz, getAlias(clazz));
205  registerClass(clazz, clazz.getName());
206  }
207  }
208 
209  /**
210  * Registers the given alias to the specified {@link
211  * ConfigurationSerializable} class
212  *
213  * @param clazz Class to register
214  * @param alias Alias to register as
215  * @see SerializableAs
216  */
217  public static void registerClass(Class<? extends ConfigurationSerializable> clazz, String alias) {
218  aliases.put(alias, clazz);
219  }
220 
221  /**
222  * Unregisters the specified alias to a {@link ConfigurationSerializable}
223  *
224  * @param alias Alias to unregister
225  */
226  public static void unregisterClass(String alias) {
227  aliases.remove(alias);
228  }
229 
230  /**
231  * Unregisters any aliases for the specified {@link
232  * ConfigurationSerializable} class
233  *
234  * @param clazz Class to unregister
235  */
236  public static void unregisterClass(Class<? extends ConfigurationSerializable> clazz) {
237  while (aliases.values().remove(clazz)) {
238  ;
239  }
240  }
241 
242  /**
243  * Attempts to get a registered {@link ConfigurationSerializable} class by
244  * its alias
245  *
246  * @param alias Alias of the serializable
247  * @return Registered class, or null if not found
248  */
249  public static Class<? extends ConfigurationSerializable> getClassByAlias(String alias) {
250  return aliases.get(alias);
251  }
252 
253  /**
254  * Gets the correct alias for the given {@link ConfigurationSerializable}
255  * class
256  *
257  * @param clazz Class to get alias for
258  * @return Alias to use for the class
259  */
260  public static String getAlias(Class<? extends ConfigurationSerializable> clazz) {
261  DelegateDeserialization delegate = clazz.getAnnotation(DelegateDeserialization.class);
262 
263  if (delegate != null) {
264  if ((delegate.value() == null) || (delegate.value() == clazz)) {
265  delegate = null;
266  } else {
267  return getAlias(delegate.value());
268  }
269  }
270 
271  if (delegate == null) {
272  SerializableAs alias = clazz.getAnnotation(SerializableAs.class);
273 
274  if ((alias != null) && (alias.value() != null)) {
275  return alias.value();
276  }
277  }
278 
279  return clazz.getName();
280  }
281 }
static ConfigurationSerializable deserializeObject(Map< String,?> args)
static ConfigurationSerializable deserializeObject(Map< String,?> args, Class<?extends ConfigurationSerializable > clazz)
static String getAlias(Class<?extends ConfigurationSerializable > clazz)
Class<?extends ConfigurationSerializable > value()
static void registerClass(Class<?extends ConfigurationSerializable > clazz)
static void unregisterClass(Class<?extends ConfigurationSerializable > clazz)
static Class<?extends ConfigurationSerializable > getClassByAlias(String alias)
static void registerClass(Class<?extends ConfigurationSerializable > clazz, String alias)