View Javadoc
1   package org.djutils.data.serialization;
2   
3   import java.lang.reflect.InvocationTargetException;
4   import java.lang.reflect.Method;
5   import java.util.LinkedHashMap;
6   import java.util.Map;
7   
8   import org.djunits.unit.Unit;
9   import org.djunits.value.vdouble.scalar.base.DoubleScalarInterface;
10  
11  /**
12   * ScalarSerializer (de)serializes DJUNITS scalars. <br>
13   * <br>
14   * Copyright (c) 2020-2021 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
15   * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
16   * distributed under a three-clause BSD-style license, which can be found at
17   * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>. <br>
18   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
19   * @author <a href="https://www.tudelft.nl/pknoppers">Peter Knoppers</a>
20   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
21   * @param <U> the unit type
22   * @param <S> the scalar type
23   */
24  public class DoubleScalarSerializer<U extends Unit<U>, S extends DoubleScalarInterface<U, S>> implements TextSerializer<S>
25  {
26      /** cache of the retrieved valueOf(String) methods for scalars based on the stored string. */
27      private static Map<String, Method> valueOfMethodCache = new LinkedHashMap<>();
28  
29      /**
30       * Serialize a DoubleScalar value to text in such a way that it can be deserialized with the corresponding deserializer. In
31       * this case, it serializes the class name of the Scalar, followed by a hash sign, followed by the printed value of the
32       * scalar including the unit. So a Length of 12.5 kilometer will return "org.djunits.value.vdouble.scalar.Length#12.5 km".
33       * @param value Object; the scalar to serialize
34       * @return String; a string representation of the value that can later be deserialized
35       */
36      @SuppressWarnings("unchecked")
37      @Override
38      public String serialize(final Object value)
39      {
40          return value.getClass().getName() + "#" + ((S) value).toTextualString();
41      }
42  
43      /**
44       * Deserialize a String to the correct DoubleScalar value in line with the DoubleScalarSerializer.serialize method. In this
45       * case, it assumes a string with the class name of the Scalar, followed by a hash sign, followed by the printed value of
46       * the scalar including the unit. So, the String "org.djunits.value.vdouble.scalar.Length#12.5 km" will be deserialized into
47       * a Length of 12500 m with LengthUnit.KILOMETER as the display unit. The method caches the valueOf(String) method for
48       * repeated use.
49       * @param text String; the text to deserialize
50       * @return S; the reconstructed scalar
51       */
52      @SuppressWarnings("unchecked")
53      @Override
54      public S deserialize(final String text)
55      {
56          String[] parts = text.split("#");
57          try
58          {
59              Method valueOfMethod = valueOfMethodCache.get(parts[0]);
60              if (valueOfMethod == null)
61              {
62                  Class<?> scalarClass = Class.forName(parts[0]);
63                  valueOfMethod = scalarClass.getDeclaredMethod("valueOf", String.class);
64                  valueOfMethodCache.put(parts[0], valueOfMethod);
65              }
66              return (S) valueOfMethodCache.get(parts[0]).invoke(null, parts[1]);
67          }
68          catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
69                  | NoSuchMethodException | SecurityException exception)
70          {
71              throw new RuntimeException(exception);
72          }
73      }
74  
75  }