[jboss-user] [Javassist user questions] - serialVersionUID issue

spampete do-not-reply at jboss.com
Thu Dec 4 04:23:42 EST 2008


Hi all, 

I have released a small memory leak detector on http://www.qarks.com web site, which is using javassist. Despite using the serialVersionUID helper, recent tests showed a remaining issue with some serializable classes during unmarshalling, with InvalidClassException due to inconsistent serialVersionUID.

I've had a look to Sun's ObjectStreamClass implementation (JDK 1.6) and found indeed some differences explaining the situation. Actually, I do not know if the issue is on Sun's side, not respecting its own spec, or not, but the fix I brough does work on my test bench. 

I'd be interested in having your feedback, all of you guys !!

Meanwhile, here is the method I changed within javassist serialVersionUID helper, which I will also send to Shigeru Chiba by email:


  | 
  | 	static long calculateDefault(CtClass clazz) throws CannotCompileException {
  | 		ByteArrayOutputStream bout;
  | 		try {
  | 			bout = new ByteArrayOutputStream();
  | 			DataOutputStream out = new DataOutputStream(bout);
  | 			ClassFile classFile = clazz.getClassFile();
  | 
  | 			String javaName = javaName(clazz);
  | 			out.writeUTF(javaName);
  | 
  | 			CtMethod[] methods = clazz.getDeclaredMethods();
  | 			
  | 			int classMods = clazz.getModifiers();
  | 			if ((classMods & Modifier.INTERFACE) != 0) {
  | 				classMods = (methods.length > 0) ?
  | 				    (classMods | Modifier.ABSTRACT) :
  | 				    (classMods & ~Modifier.ABSTRACT);
  | 			    }
  | 			out.writeInt(classMods);
  | 
  | 			if (!clazz.isArray()){
  | 			String[] interfaces = classFile.getInterfaces();
  | 			for (int i = 0; i < interfaces.length; ++i)
  | 				interfaces = javaName(interfaces);
  | 
  | 			Arrays.sort(interfaces);
  | 			for (int i = 0; i < interfaces.length; ++i) {
  | 				out.writeUTF(interfaces);
  | 			}
  | 			}
  | 
  | 			CtField[] fields = clazz.getDeclaredFields();
  | 			Arrays.sort(fields, new Comparator() {
  | 				public int compare(Object o1, Object o2) {
  | 					CtField field1 = (CtField) o1;
  | 					CtField field2 = (CtField) o2;
  | 					return field1.getName().compareTo(field2.getName());
  | 				}
  | 
  | 			});
  | 			for (int i = 0; i < fields.length; ++i) {
  | 				CtField field = fields;
  | 				int mods = field.getModifiers();
  | 				if (((mods & 0x2) == 0) || ((mods & 0x88) == 0)) {
  | 					out.writeUTF(field.getName());
  | 					out.writeInt(mods);
  | 					out.writeUTF(field.getFieldInfo2().getDescriptor());
  | 				}
  | 
  | 			}
  | 
  | 			if (classFile.getStaticInitializer() != null) {
  | 				out.writeUTF("<clinit>");
  | 				out.writeInt(8);
  | 				out.writeUTF("()V");
  | 			}
  | 
  | 			CtConstructor[] constructors = clazz.getDeclaredConstructors();
  | 			Arrays.sort(constructors, new Comparator() {
  | 				public int compare(Object o1, Object o2) {
  | 					CtConstructor c1 = (CtConstructor) o1;
  | 					CtConstructor c2 = (CtConstructor) o2;
  | 					return c1.getMethodInfo2().getDescriptor().compareTo(
  | 							c2.getMethodInfo2().getDescriptor());
  | 				}
  | 
  | 			});
  | 			for (int i = 0; i < constructors.length; ++i) {
  | 				CtConstructor constructor = constructors;
  | 				int mods = constructor.getModifiers();
  | 				if ((mods & 0x2) == 0) {
  | 					out.writeUTF("<init>");
  | 					out.writeInt(mods);
  | 					out.writeUTF(constructor.getMethodInfo2().getDescriptor()
  | 							.replace('/', '.'));
  | 				}
  | 
  | 			}
  | 
  | 			//CtMethod[] methods = clazz.getDeclaredMethods();
  | 			Arrays.sort(methods, new Comparator() {
  | 				public int compare(Object o1, Object o2) {
  | 					CtMethod m1 = (CtMethod) o1;
  | 					CtMethod m2 = (CtMethod) o2;
  | 					int value = m1.getName().compareTo(m2.getName());
  | 					if (value == 0) {
  | 						value = m1.getMethodInfo2().getDescriptor().compareTo(
  | 								m2.getMethodInfo2().getDescriptor());
  | 					}
  | 
  | 					return value;
  | 				}
  | 
  | 			});
  | 			for (int i = 0; i < methods.length; ++i) {
  | 				CtMethod method = methods;
  | 				int mods = method.getModifiers() &
  | 				(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
  | 						Modifier.STATIC | Modifier.FINAL |
  | 						Modifier.SYNCHRONIZED | Modifier.NATIVE |
  | 						Modifier.ABSTRACT | Modifier.STRICT);
  | 				
  | 				if ((mods & Modifier.PRIVATE) == 0) {
  | 					out.writeUTF(method.getName());
  | 					out.writeInt(mods);
  | 					out.writeUTF(method.getMethodInfo2().getDescriptor()
  | 							.replace('/', '.'));
  | 				}
  | 
  | 			}
  | 
  | 			out.flush();
  | 			
  | 			MessageDigest digest = MessageDigest.getInstance("SHA");
  | 			byte[] digested = digest.digest(bout.toByteArray());
  | 			long hash = 0L;
  | 			for (int i = Math.min(digested.length, 8) - 1; i >= 0; --i)
  | 				hash = hash << 8 | digested & 0xFF;
  | 
  | 			return hash;
  | 		} catch (IOException e) {
  | 			throw new CannotCompileException(e);
  | 		} catch (NoSuchAlgorithmException e) {
  | 			throw new CannotCompileException(e);
  | 		}
  | 	}
  | 
  | 

kind regards,

Pierre

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4194254#4194254

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4194254



More information about the jboss-user mailing list