X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;f=gson%2Fcom%2Fgoogle%2Fgson%2Finternal%2FUnsafeAllocator.java;fp=gson%2Fcom%2Fgoogle%2Fgson%2Finternal%2FUnsafeAllocator.java;h=d69e3dc2e1711f6d09668d0a844e16cfcf97a713;hb=5c86ae2f45d293408d98a291e826948052d207bc;hp=0000000000000000000000000000000000000000;hpb=5cf4714f0675349ed599707e024cf0e70fe114b2;p=unical.git diff --git a/gson/com/google/gson/internal/UnsafeAllocator.java b/gson/com/google/gson/internal/UnsafeAllocator.java new file mode 100644 index 0000000..d69e3dc --- /dev/null +++ b/gson/com/google/gson/internal/UnsafeAllocator.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.gson.internal; + +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * Do sneaky things to allocate objects without invoking their constructors. + * + * @author Joel Leitch + * @author Jesse Wilson + */ +public abstract class UnsafeAllocator { + public abstract T newInstance(Class c) throws Exception; + + public static UnsafeAllocator create() { + // try JVM + // public class Unsafe { + // public Object allocateInstance(Class type); + // } + try { + Class unsafeClass = Class.forName("sun.misc.Unsafe"); + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + final Object unsafe = f.get(null); + final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class); + return new UnsafeAllocator() { + @Override + @SuppressWarnings("unchecked") + public T newInstance(Class c) throws Exception { + return (T) allocateInstance.invoke(unsafe, c); + } + }; + } catch (Exception ignored) { + } + + // try dalvikvm, pre-gingerbread + // public class ObjectInputStream { + // private static native Object newInstance( + // Class instantiationClass, Class constructorClass); + // } + try { + final Method newInstance = ObjectInputStream.class + .getDeclaredMethod("newInstance", Class.class, Class.class); + newInstance.setAccessible(true); + return new UnsafeAllocator() { + @Override + @SuppressWarnings("unchecked") + public T newInstance(Class c) throws Exception { + return (T) newInstance.invoke(null, c, Object.class); + } + }; + } catch (Exception ignored) { + } + + // try dalvikvm, post-gingerbread + // public class ObjectStreamClass { + // private static native int getConstructorId(Class c); + // private static native Object newInstance(Class instantiationClass, int methodId); + // } + try { + Method getConstructorId = ObjectStreamClass.class + .getDeclaredMethod("getConstructorId", Class.class); + getConstructorId.setAccessible(true); + final int constructorId = (Integer) getConstructorId.invoke(null, Object.class); + final Method newInstance = ObjectStreamClass.class + .getDeclaredMethod("newInstance", Class.class, int.class); + newInstance.setAccessible(true); + return new UnsafeAllocator() { + @Override + @SuppressWarnings("unchecked") + public T newInstance(Class c) throws Exception { + return (T) newInstance.invoke(null, c, constructorId); + } + }; + } catch (Exception ignored) { + } + + // give up + return new UnsafeAllocator() { + @Override + public T newInstance(Class c) { + throw new UnsupportedOperationException("Cannot allocate " + c); + } + }; + } +}