package org.sql2o.reflection;

import org.sql2o.Sql2oException;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

@SuppressWarnings("Unsafe")
public class UnsafeFieldSetterFactory implements FieldSetterFactory, ObjectConstructorFactory {
    private final static Unsafe theUnsafe;
    static {
        try {
            Class unsafeClass = Class.forName("sun.misc.Unsafe");
            Field declaredField = unsafeClass.getDeclaredField("theUnsafe");
            declaredField.setAccessible(true);
            theUnsafe = (Unsafe) declaredField.get(null);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public Setter newSetter(final Field field) {
        final Class type = field.getClass();
        final long offset = theUnsafe.objectFieldOffset(field);

        if (!Modifier.isVolatile(field.getModifiers())) {
            if (type == Boolean.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putBoolean(obj, offset, (Boolean) value);
                    }

                    public Class getType() {
                        return Boolean.TYPE;
                    }
                };
            }
            if (type == Character.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putChar(obj, offset, (Character) value);
                    }

                    public Class getType() {
                        return Character.TYPE;
                    }
                };
            }
            if (type == Byte.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putByte(obj, offset, ((Number) value).byteValue());
                    }

                    public Class getType() {
                        return Byte.TYPE;
                    }
                };
            }
            if (type == Short.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putShort(obj, offset, ((Number) value).shortValue());
                    }

                    public Class getType() {
                        return Short.TYPE;
                    }
                };
            }
            if (type == Integer.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putInt(obj, offset, ((Number) value).intValue());
                    }

                    public Class getType() {
                        return Integer.TYPE;
                    }
                };
            }
            if (type == Long.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putLong(obj, offset, ((Number) value).longValue());
                    }

                    public Class getType() {
                        return Long.TYPE;
                    }
                };
            }
            if (type == Float.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putFloat(obj, offset, ((Number) value).floatValue());
                    }

                    public Class getType() {
                        return Float.TYPE;
                    }
                };
            }
            if (type == Double.TYPE) {
                return new Setter() {
                    public void setProperty(Object obj, Object value) {
                        if (value == null) return;
                        theUnsafe.putDouble(obj, offset, ((Number) value).doubleValue());
                    }

                    public Class getType() {
                        return Double.TYPE;
                    }
                };
            }
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    theUnsafe.putObject(obj, offset, value);
                }

                public Class getType() {
                    return type;
                }
            };
        }

        if (type == Boolean.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putBooleanVolatile(obj, offset, (Boolean) value);
                }

                public Class getType() {
                    return Boolean.TYPE;
                }
            };
        }
        if (type == Character.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putCharVolatile(obj, offset, (Character) value);
                }

                public Class getType() {
                    return Character.TYPE;
                }
            };
        }
        if (type == Byte.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putByteVolatile(obj, offset, ((Number) value).byteValue());
                }

                public Class getType() {
                    return Byte.TYPE;
                }
            };
        }
        if (type == Short.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putShortVolatile(obj, offset, ((Number) value).shortValue());
                }

                public Class getType() {
                    return Short.TYPE;
                }
            };
        }
        if (type == Integer.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putIntVolatile(obj, offset, ((Number) value).intValue());
                }

                public Class getType() {
                    return Integer.TYPE;
                }
            };
        }
        if (type == Long.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putLongVolatile(obj, offset, ((Number) value).longValue());
                }

                public Class getType() {
                    return Long.TYPE;
                }
            };
        }
        if (type == Float.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putFloatVolatile(obj, offset, ((Number) value).floatValue());
                }

                public Class getType() {
                    return Float.TYPE;
                }
            };
        }
        if (type == Double.TYPE) {
            return new Setter() {
                public void setProperty(Object obj, Object value) {
                    if (value == null) return;
                    theUnsafe.putDoubleVolatile(obj, offset, ((Number) value).doubleValue());
                }

                public Class getType() {
                    return Double.TYPE;
                }
            };
        }
        return new Setter() {
            public void setProperty(Object obj, Object value) {
                theUnsafe.putObjectVolatile(obj, offset, value);
            }

            public Class getType() {
                return type;
            }
        };
    }

    public ObjectConstructor newConstructor(final Class<?> clazz) {
        return new ObjectConstructor() {
            public Object newInstance() {
                try {
                    return theUnsafe.allocateInstance(clazz);
                } catch (InstantiationException e) {
                    throw new Sql2oException("Could not create a new instance of class " + clazz, e);
                }
            }
        };
    }
}

@@ -769,21 +769,20 @@
 ield.get
-Class
+Type
 ();%0A    

fix unsafe factory