| /* |
| * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved. |
| * |
| * The Apache Software License, Version 1.1 |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Caucho Technology (http://www.caucho.com/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "Burlap", "Resin", and "Caucho" must not be used to |
| * endorse or promote products derived from this software without prior |
| * written permission. For written permission, please contact |
| * info@caucho.com. |
| * |
| * 5. Products derived from this software may not be called "Resin" |
| * nor may "Resin" appear in their names without prior written |
| * permission of Caucho Technology. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
| * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * @author Scott Ferguson |
| */ |
| |
| package com.alibaba.com.caucho.hessian.io; |
| |
| import com.alibaba.com.caucho.hessian.HessianException; |
| |
| import java.io.IOException; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * Serializing a Java annotation |
| */ |
| public class AnnotationSerializer extends AbstractSerializer { |
| private static final Logger log |
| = Logger.getLogger(AnnotationSerializer.class.getName()); |
| |
| private static Object[] NULL_ARGS = new Object[0]; |
| |
| private Class _annType; |
| private Method[] _methods; |
| private MethodSerializer[] _methodSerializers; |
| |
| public AnnotationSerializer(Class annType) { |
| if (!Annotation.class.isAssignableFrom(annType)) { |
| throw new IllegalStateException(annType.getName() + " is invalid because it is not a java.lang.annotation.Annotation"); |
| } |
| } |
| |
| private static MethodSerializer getMethodSerializer(Class type) { |
| if (int.class.equals(type) |
| || byte.class.equals(type) |
| || short.class.equals(type) |
| || int.class.equals(type)) { |
| return IntMethodSerializer.SER; |
| } else if (long.class.equals(type)) { |
| return LongMethodSerializer.SER; |
| } else if (double.class.equals(type) || |
| float.class.equals(type)) { |
| return DoubleMethodSerializer.SER; |
| } else if (boolean.class.equals(type)) { |
| return BooleanMethodSerializer.SER; |
| } else if (String.class.equals(type)) { |
| return StringMethodSerializer.SER; |
| } else if (java.util.Date.class.equals(type) |
| || java.sql.Date.class.equals(type) |
| || java.sql.Timestamp.class.equals(type) |
| || java.sql.Time.class.equals(type)) { |
| return DateMethodSerializer.SER; |
| } else |
| return MethodSerializer.SER; |
| } |
| |
| static HessianException error(Method method, Throwable cause) { |
| String msg = (method.getDeclaringClass().getSimpleName() |
| + "." + method.getName() + "(): " + cause); |
| |
| throw new HessianMethodSerializationException(msg, cause); |
| } |
| |
| public void writeObject(Object obj, AbstractHessianOutput out) |
| throws IOException { |
| if (out.addRef(obj)) { |
| return; |
| } |
| |
| init(((Annotation) obj).annotationType()); |
| |
| int ref = out.writeObjectBegin(_annType.getName()); |
| |
| if (ref < -1) { |
| writeObject10(obj, out); |
| } else { |
| if (ref == -1) { |
| writeDefinition20(out); |
| out.writeObjectBegin(_annType.getName()); |
| } |
| |
| writeInstance(obj, out); |
| } |
| } |
| |
| protected void writeObject10(Object obj, AbstractHessianOutput out) |
| throws IOException { |
| for (int i = 0; i < _methods.length; i++) { |
| Method method = _methods[i]; |
| |
| out.writeString(method.getName()); |
| |
| _methodSerializers[i].serialize(out, obj, method); |
| } |
| |
| out.writeMapEnd(); |
| } |
| |
| private void writeDefinition20(AbstractHessianOutput out) |
| throws IOException { |
| out.writeClassFieldLength(_methods.length); |
| |
| for (int i = 0; i < _methods.length; i++) { |
| Method method = _methods[i]; |
| |
| out.writeString(method.getName()); |
| } |
| } |
| |
| public void writeInstance(Object obj, AbstractHessianOutput out) |
| throws IOException { |
| for (int i = 0; i < _methods.length; i++) { |
| Method method = _methods[i]; |
| |
| _methodSerializers[i].serialize(out, obj, method); |
| } |
| } |
| |
| private void init(Class cl) { |
| synchronized (this) { |
| if (_annType != null) |
| return; |
| |
| _annType = cl; |
| |
| ArrayList methods = new ArrayList(); |
| |
| for (Method method : _annType.getDeclaredMethods()) { |
| if (method.getName().equals("hashCode") |
| || method.getName().equals("toString") |
| || method.getName().equals("annotationType")) { |
| continue; |
| } |
| |
| if (method.getParameterTypes().length != 0) |
| continue; |
| |
| methods.add(method); |
| |
| method.setAccessible(true); |
| } |
| |
| if (_annType == null) |
| throw new IllegalStateException(cl.getName() + " is invalid because it does not have a valid annotationType()"); |
| |
| _methods = new Method[methods.size()]; |
| methods.toArray(_methods); |
| |
| _methodSerializers = new MethodSerializer[_methods.length]; |
| |
| for (int i = 0; i < _methods.length; i++) { |
| _methodSerializers[i] = getMethodSerializer(_methods[i].getReturnType()); |
| } |
| } |
| } |
| |
| private Class getAnnotationType(Class cl) { |
| if (cl == null) |
| return null; |
| |
| if (Annotation.class.equals(cl.getSuperclass())) |
| return cl; |
| |
| Class ifaces[] = cl.getInterfaces(); |
| |
| if (ifaces != null) { |
| for (Class iface : ifaces) { |
| if (iface.equals(Annotation.class)) |
| return cl; |
| |
| Class annType = getAnnotationType(iface); |
| |
| if (annType != null) |
| return annType; |
| } |
| } |
| |
| return getAnnotationType(cl.getSuperclass()); |
| } |
| |
| static class MethodSerializer { |
| static final MethodSerializer SER = new MethodSerializer(); |
| |
| void serialize(AbstractHessianOutput out, Object obj, Method method) |
| throws IOException { |
| Object value = null; |
| |
| try { |
| value = method.invoke(obj); |
| } catch (InvocationTargetException e) { |
| throw error(method, e.getCause()); |
| } catch (IllegalAccessException e) { |
| log.log(Level.FINE, e.toString(), e); |
| } |
| |
| try { |
| out.writeObject(value); |
| } catch (Exception e) { |
| throw error(method, e); |
| } |
| } |
| } |
| |
| static class BooleanMethodSerializer extends MethodSerializer { |
| static final MethodSerializer SER = new BooleanMethodSerializer(); |
| |
| void serialize(AbstractHessianOutput out, Object obj, Method method) |
| throws IOException { |
| boolean value = false; |
| |
| try { |
| value = (Boolean) method.invoke(obj); |
| } catch (InvocationTargetException e) { |
| throw error(method, e.getCause()); |
| } catch (IllegalAccessException e) { |
| log.log(Level.FINE, e.toString(), e); |
| } |
| |
| out.writeBoolean(value); |
| } |
| } |
| |
| static class IntMethodSerializer extends MethodSerializer { |
| static final MethodSerializer SER = new IntMethodSerializer(); |
| |
| void serialize(AbstractHessianOutput out, Object obj, Method method) |
| throws IOException { |
| int value = 0; |
| |
| try { |
| value = (Integer) method.invoke(obj); |
| } catch (InvocationTargetException e) { |
| throw error(method, e.getCause()); |
| } catch (IllegalAccessException e) { |
| log.log(Level.FINE, e.toString(), e); |
| } |
| |
| out.writeInt(value); |
| } |
| } |
| |
| static class LongMethodSerializer extends MethodSerializer { |
| static final MethodSerializer SER = new LongMethodSerializer(); |
| |
| void serialize(AbstractHessianOutput out, Object obj, Method method) |
| throws IOException { |
| long value = 0; |
| |
| try { |
| value = (Long) method.invoke(obj); |
| } catch (InvocationTargetException e) { |
| throw error(method, e.getCause()); |
| } catch (IllegalAccessException e) { |
| log.log(Level.FINE, e.toString(), e); |
| } |
| |
| out.writeLong(value); |
| } |
| } |
| |
| static class DoubleMethodSerializer extends MethodSerializer { |
| static final MethodSerializer SER = new DoubleMethodSerializer(); |
| |
| void serialize(AbstractHessianOutput out, Object obj, Method method) |
| throws IOException { |
| double value = 0; |
| |
| try { |
| value = (Double) method.invoke(obj); |
| } catch (InvocationTargetException e) { |
| throw error(method, e.getCause()); |
| } catch (IllegalAccessException e) { |
| log.log(Level.FINE, e.toString(), e); |
| } |
| |
| out.writeDouble(value); |
| } |
| } |
| |
| static class StringMethodSerializer extends MethodSerializer { |
| static final MethodSerializer SER = new StringMethodSerializer(); |
| |
| void serialize(AbstractHessianOutput out, Object obj, Method method) |
| throws IOException { |
| String value = null; |
| |
| try { |
| value = (String) method.invoke(obj); |
| } catch (InvocationTargetException e) { |
| throw error(method, e.getCause()); |
| } catch (IllegalAccessException e) { |
| log.log(Level.FINE, e.toString(), e); |
| } |
| |
| out.writeString(value); |
| } |
| } |
| |
| static class DateMethodSerializer extends MethodSerializer { |
| static final MethodSerializer SER = new DateMethodSerializer(); |
| |
| void serialize(AbstractHessianOutput out, Object obj, Method method) |
| throws IOException { |
| java.util.Date value = null; |
| |
| try { |
| value = (java.util.Date) method.invoke(obj); |
| } catch (InvocationTargetException e) { |
| throw error(method, e.getCause()); |
| } catch (IllegalAccessException e) { |
| log.log(Level.FINE, e.toString(), e); |
| } |
| |
| if (value == null) |
| out.writeNull(); |
| else |
| out.writeUTCDate(value.getTime()); |
| } |
| } |
| } |