View Javadoc
1   /**
2    * Copyright 2014 Internet2
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   * Copyright (C) 2004, 2005 Joe Walnes.
18   * Copyright (C) 2006, 2007 XStream Committers.
19   * All rights reserved.
20   *
21   * The software in this package is published under the terms of the BSD
22   * style license a copy of which has been included with this distribution in
23   * the LICENSE.txt file.
24   * 
25   * Created on 23. August 2004 by Joe Walnes
26   */
27  package edu.internet2.middleware.grouperClientExt.com.thoughtworks.xstream.converters.reflection;
28  
29  import java.io.ObjectInputStream;
30  import java.io.ObjectOutputStream;
31  import java.lang.reflect.InvocationTargetException;
32  import java.lang.reflect.Method;
33  import java.util.Collections;
34  import java.util.HashMap;
35  import java.util.Map;
36  
37  import edu.internet2.middleware.grouperClientExt.com.thoughtworks.xstream.converters.ConversionException;
38  
39  /**
40   * Convenience wrapper to invoke special serialization methods on objects (and perform reflection caching).
41   *
42   * @author Joe Walnes
43   */
44  public class SerializationMethodInvoker {
45  
46      private Map cache = Collections.synchronizedMap(new HashMap());
47      private static final Object NO_METHOD = new Object();
48      private static final Object[] EMPTY_ARGS = new Object[0];
49  
50      /**
51       * Resolves an object as native serialization does by calling readResolve(), if available.
52       */
53      public Object callReadResolve(Object result) {
54          if (result == null) {
55              return null;
56          } else {
57              Method readResolveMethod = getMethod(result.getClass(), "readResolve", null, true);
58              if (readResolveMethod != null) {
59                  try {
60                      return readResolveMethod.invoke(result, EMPTY_ARGS);
61                  } catch (IllegalAccessException e) {
62                      throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", e);
63                  } catch (InvocationTargetException e) {
64                      throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", e.getTargetException());
65                  }
66              } else {
67                  return result;
68              }
69          }
70      }
71  
72      public Object callWriteReplace(Object object) {
73          if (object == null) {
74              return null;
75          } else {
76              Method writeReplaceMethod = getMethod(object.getClass(), "writeReplace", null, true);
77              if (writeReplaceMethod != null) {
78                  try {
79                      Object[] EMPTY_ARGS = new Object[0];
80                      return writeReplaceMethod.invoke(object, EMPTY_ARGS);
81                  } catch (IllegalAccessException e) {
82                      throw new ObjectAccessException("Could not call " + object.getClass().getName() + ".writeReplace()", e);
83                  } catch (InvocationTargetException e) {
84                      throw new ObjectAccessException("Could not call " + object.getClass().getName() + ".writeReplace()", e.getTargetException());
85                  }
86              } else {
87                  return object;
88              }
89          }
90      }
91  
92      public boolean supportsReadObject(Class type, boolean includeBaseClasses) {
93          return getMethod(type, "readObject", new Class[]{ObjectInputStream.class}, includeBaseClasses) != null;
94      }
95  
96      public void callReadObject(Class type, Object object, ObjectInputStream stream) {
97          try {
98              Method readObjectMethod = getMethod(type, "readObject", new Class[]{ObjectInputStream.class}, false);
99              readObjectMethod.invoke(object, new Object[]{stream});
100         } catch (IllegalAccessException e) {
101             throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e);
102         } catch (InvocationTargetException e) {
103             throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e.getTargetException());
104         }
105     }
106 
107     public boolean supportsWriteObject(Class type, boolean includeBaseClasses) {
108         return getMethod(type, "writeObject", new Class[]{ObjectOutputStream.class}, includeBaseClasses) != null;
109     }
110 
111     public void callWriteObject(Class type, Object instance, ObjectOutputStream stream) {
112         try {
113             Method readObjectMethod = getMethod(type, "writeObject", new Class[]{ObjectOutputStream.class}, false);
114             readObjectMethod.invoke(instance, new Object[]{stream});
115         } catch (IllegalAccessException e) {
116             throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e);
117         } catch (InvocationTargetException e) {
118             throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e.getTargetException());
119         }
120     }
121 
122     private Method getMethod(Class type, String name, Class[] parameterTypes, boolean includeBaseclasses) {
123         Object key = type.getName() + "." + name + "." + includeBaseclasses;
124         if (cache.containsKey(key)) {
125             Object result = cache.get(key);
126             return (Method) (result == NO_METHOD ? null : result);
127         }
128         if (includeBaseclasses) {
129             while (type != null) {
130                 try {
131                     Method result = type.getDeclaredMethod(name, parameterTypes);
132                     result.setAccessible(true);
133                     cache.put(key, result);
134                     return result;
135                 } catch (NoSuchMethodException e) {
136                     type = type.getSuperclass();
137                 }
138             }
139             cache.put(key, NO_METHOD);
140             return null;
141         } else {
142             try {
143                 Method result = type.getDeclaredMethod(name, parameterTypes);
144                 result.setAccessible(true);
145                 cache.put(key, result);
146                 return result;
147             } catch (NoSuchMethodException e) {
148                 cache.put(key, NO_METHOD);
149                 return null;
150             }
151         }
152     }
153 
154 }