github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgRpc/kmgRpcJava/java/src/com/google/gson/internal/ConstructorConstructor.java (about)

     1  /*
     2   * Copyright (C) 2011 Google Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package com.google.gson.internal;
    18  
    19  import com.google.gson.InstanceCreator;
    20  import com.google.gson.JsonIOException;
    21  import com.google.gson.reflect.TypeToken;
    22  
    23  import java.lang.reflect.Constructor;
    24  import java.lang.reflect.InvocationTargetException;
    25  import java.lang.reflect.ParameterizedType;
    26  import java.lang.reflect.Type;
    27  import java.util.ArrayList;
    28  import java.util.Collection;
    29  import java.util.EnumSet;
    30  import java.util.LinkedHashMap;
    31  import java.util.LinkedHashSet;
    32  import java.util.LinkedList;
    33  import java.util.Map;
    34  import java.util.Queue;
    35  import java.util.Set;
    36  import java.util.SortedMap;
    37  import java.util.SortedSet;
    38  import java.util.TreeMap;
    39  import java.util.TreeSet;
    40  
    41  /**
    42   * Returns a function that can construct an instance of a requested type.
    43   */
    44  public final class ConstructorConstructor {
    45    private final Map<Type, InstanceCreator<?>> instanceCreators;
    46  
    47    public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {
    48      this.instanceCreators = instanceCreators;
    49    }
    50  
    51    public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
    52      final Type type = typeToken.getType();
    53      final Class<? super T> rawType = typeToken.getRawType();
    54  
    55      // first try an instance creator
    56  
    57      @SuppressWarnings("unchecked") // types must agree
    58      final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
    59      if (typeCreator != null) {
    60        return new ObjectConstructor<T>() {
    61          public T construct() {
    62            return typeCreator.createInstance(type);
    63          }
    64        };
    65      }
    66  
    67      // Next try raw type match for instance creators
    68      @SuppressWarnings("unchecked") // types must agree
    69      final InstanceCreator<T> rawTypeCreator =
    70          (InstanceCreator<T>) instanceCreators.get(rawType);
    71      if (rawTypeCreator != null) {
    72        return new ObjectConstructor<T>() {
    73          public T construct() {
    74            return rawTypeCreator.createInstance(type);
    75          }
    76        };
    77      }
    78  
    79      ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
    80      if (defaultConstructor != null) {
    81        return defaultConstructor;
    82      }
    83  
    84      ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
    85      if (defaultImplementation != null) {
    86        return defaultImplementation;
    87      }
    88  
    89      // finally try unsafe
    90      return newUnsafeAllocator(type, rawType);
    91    }
    92  
    93    private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
    94      try {
    95        final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
    96        if (!constructor.isAccessible()) {
    97          constructor.setAccessible(true);
    98        }
    99        return new ObjectConstructor<T>() {
   100          @SuppressWarnings("unchecked") // T is the same raw type as is requested
   101          public T construct() {
   102            try {
   103              Object[] args = null;
   104              return (T) constructor.newInstance(args);
   105            } catch (InstantiationException e) {
   106              // TODO: JsonParseException ?
   107              throw new RuntimeException("Failed to invoke " + constructor + " with no args", e);
   108            } catch (InvocationTargetException e) {
   109              // TODO: don't wrap if cause is unchecked!
   110              // TODO: JsonParseException ?
   111              throw new RuntimeException("Failed to invoke " + constructor + " with no args",
   112                  e.getTargetException());
   113            } catch (IllegalAccessException e) {
   114              throw new AssertionError(e);
   115            }
   116          }
   117        };
   118      } catch (NoSuchMethodException e) {
   119        return null;
   120      }
   121    }
   122  
   123    /**
   124     * Constructors for common interface types like Map and List and their
   125     * subytpes.
   126     */
   127    @SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is
   128    private <T> ObjectConstructor<T> newDefaultImplementationConstructor(
   129        final Type type, Class<? super T> rawType) {
   130      if (Collection.class.isAssignableFrom(rawType)) {
   131        if (SortedSet.class.isAssignableFrom(rawType)) {
   132          return new ObjectConstructor<T>() {
   133            public T construct() {
   134              return (T) new TreeSet<Object>();
   135            }
   136          };
   137        } else if (EnumSet.class.isAssignableFrom(rawType)) {
   138          return new ObjectConstructor<T>() {
   139            @SuppressWarnings("rawtypes")
   140            public T construct() {
   141              if (type instanceof ParameterizedType) {
   142                Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
   143                if (elementType instanceof Class) {
   144                  return (T) EnumSet.noneOf((Class)elementType);
   145                } else {
   146                  throw new JsonIOException("Invalid EnumSet type: " + type.toString());
   147                }
   148              } else {
   149                throw new JsonIOException("Invalid EnumSet type: " + type.toString());
   150              }
   151            }
   152          };
   153        } else if (Set.class.isAssignableFrom(rawType)) {
   154          return new ObjectConstructor<T>() {
   155            public T construct() {
   156              return (T) new LinkedHashSet<Object>();
   157            }
   158          };
   159        } else if (Queue.class.isAssignableFrom(rawType)) {
   160          return new ObjectConstructor<T>() {
   161            public T construct() {
   162              return (T) new LinkedList<Object>();
   163            }
   164          };
   165        } else {
   166          return new ObjectConstructor<T>() {
   167            public T construct() {
   168              return (T) new ArrayList<Object>();
   169            }
   170          };
   171        }
   172      }
   173  
   174      if (Map.class.isAssignableFrom(rawType)) {
   175        if (SortedMap.class.isAssignableFrom(rawType)) {
   176          return new ObjectConstructor<T>() {
   177            public T construct() {
   178              return (T) new TreeMap<Object, Object>();
   179            }
   180          };
   181        } else if (type instanceof ParameterizedType && !(String.class.isAssignableFrom(
   182            TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType()))) {
   183          return new ObjectConstructor<T>() {
   184            public T construct() {
   185              return (T) new LinkedHashMap<Object, Object>();
   186            }
   187          };
   188        } else {
   189          return new ObjectConstructor<T>() {
   190            public T construct() {
   191              return (T) new LinkedTreeMap<String, Object>();
   192            }
   193          };
   194        }
   195      }
   196  
   197      return null;
   198    }
   199  
   200    private <T> ObjectConstructor<T> newUnsafeAllocator(
   201        final Type type, final Class<? super T> rawType) {
   202      return new ObjectConstructor<T>() {
   203        private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
   204        @SuppressWarnings("unchecked")
   205        public T construct() {
   206          try {
   207            Object newInstance = unsafeAllocator.newInstance(rawType);
   208            return (T) newInstance;
   209          } catch (Exception e) {
   210            throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
   211                + "Register an InstanceCreator with Gson for this type may fix this problem."), e);
   212          }
   213        }
   214      };
   215    }
   216  
   217    @Override public String toString() {
   218      return instanceCreators.toString();
   219    }
   220  }