Browse Source

101411: -XaddSerialVersionUID

tags/POST_MEMORY_CHANGES
aclement 18 years ago
parent
commit
6e6658a5e9

+ 159
- 1
bcel-builder/src/org/aspectj/apache/bcel/generic/ClassGen.java View File

@@ -54,7 +54,14 @@ package org.aspectj.apache.bcel.generic;
* <http://www.apache.org/>.
*/

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Modifier;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

@@ -77,8 +84,10 @@ import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
* existing java class (file).
*
* @see JavaClass
* @version $Id: ClassGen.java,v 1.5 2005/03/10 12:15:04 aclement Exp $
* @version $Id: ClassGen.java,v 1.6 2006/03/09 17:25:48 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*
* Upgraded, Andy Clement 9th Mar 06 - calculates SUID
*/
public class ClassGen extends AccessFlags implements Cloneable {
/* Corresponds to the fields found in a JavaClass object.
@@ -538,4 +547,153 @@ public class ClassGen extends AccessFlags implements Cloneable {
public final boolean isEnum() {
return (access_flags & Constants.ACC_ENUM) != 0;
}
/**
* Calculate the SerialVersionUID for a class.
*/
public long getSUID() {
try {
Field[] fields = getFields();
Method[] methods = getMethods();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
// 1. classname
dos.writeUTF(getClassName());
// 2. classmodifiers: ACC_PUBLIC, ACC_FINAL, ACC_INTERFACE, and ACC_ABSTRACT
int classmods = 0;
classmods|=(isPublic()?Constants.ACC_PUBLIC:0);
classmods|=(isFinal()?Constants.ACC_FINAL:0);
classmods|=(isInterface()?Constants.ACC_INTERFACE:0);
if (isInterface() && isAbstract()) { // remove abstract if we have it but have no methods
if (methods.length>0) classmods|=Constants.ACC_ABSTRACT;
}
dos.writeInt(classmods);
// 3. ordered list of interfaces
List list = new ArrayList();
String[] names = getInterfaceNames();
if (names!=null) {
Arrays.sort(names);
for (int i = 0; i < names.length; i++) dos.writeUTF(names[i]);
}
// 4. ordered list of fields (ignoring private static and private transient fields):
// (relevant modifiers are ACC_PUBLIC, ACC_PRIVATE,
// ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE,
// ACC_TRANSIENT)
list.clear();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (!(field.isPrivate() && field.isStatic()) &&
!(field.isPrivate() && field.isTransient())) list.add(field);
}
Collections.sort(list,new FieldComparator());
int relevantFlags = Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED |
Constants.ACC_STATIC | Constants.ACC_FINAL | Constants.ACC_VOLATILE | Constants.ACC_TRANSIENT;
for (Iterator iter = list.iterator(); iter.hasNext();) {
Field f = (Field) iter.next();
dos.writeUTF(f.getName());
dos.writeInt(relevantFlags&f.getModifiers());
dos.writeUTF(f.getType().getSignature());
}

// some up front method processing: discover clinit, init and ordinary methods of interest:
list.clear(); // now used for methods
List ctors = new ArrayList();
boolean hasClinit = false;
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
boolean couldBeInitializer = m.getName().charAt(0)=='<';
if (couldBeInitializer && m.getName().equals("<clinit>")) {
hasClinit=true;
} else if (couldBeInitializer && m.getName().equals("<init>")) {
if (!m.isPrivate()) ctors.add(m);
} else {
if (!m.isPrivate()) list.add(m);
}
}
Collections.sort(ctors, new ConstructorComparator());
Collections.sort(list, new MethodComparator());
// 5. If a class initializer exists, write out the following:
// 1. The name of the method, <clinit>.
// 2. The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer.
// 3. The descriptor of the method, ()V.
if (hasClinit) {
dos.writeUTF("<clinit>");
dos.writeInt(Modifier.STATIC);
dos.writeUTF("()V");
}
// for methods and constructors:
// ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED,
// ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT
relevantFlags =
Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED |
Constants.ACC_STATIC | Constants.ACC_FINAL | Constants.ACC_SYNCHRONIZED |
Constants.ACC_NATIVE | Constants.ACC_ABSTRACT | Constants.ACC_STRICT;
// 6. sorted non-private constructors
for (Iterator iter = ctors.iterator(); iter.hasNext();) {
Method m = (Method) iter.next();
dos.writeUTF(m.getName()); // <init>
dos.writeInt(relevantFlags & m.getModifiers());
dos.writeUTF(m.getSignature().replace('/','.'));
}

// 7. sorted non-private methods
for (Iterator iter = list.iterator(); iter.hasNext();) {
Method m = (Method) iter.next();
dos.writeUTF(m.getName());
dos.writeInt(relevantFlags & m.getModifiers());
dos.writeUTF(m.getSignature().replace('/','.'));
}
dos.flush();
dos.close();
byte[] bs = baos.toByteArray();
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] result = md.digest(bs);
long suid = 0L;
int pos = result.length>8?7:result.length-1; // use the bytes we have
while (pos>=0) {
suid = suid<<8 | ((long)result[pos--]&0xff);
}

// if it was definetly 8 everytime...
// long suid = ((long)(sha[0]&0xff) | (long)(sha[1]&0xff) << 8 |
// (long)(sha[2]&0xff) << 16 | (long)(sha[3]&0xff) << 24 |
// (long)(sha[4]&0xff) << 32 | (long)(sha[5]&0xff) << 40 |
// (long)(sha[6]&0xff) << 48 | (long)(sha[7]&0xff) << 56);
return suid;
} catch (Exception e) {
System.err.println("Unable to calculate suid for "+getClassName());
throw new RuntimeException(e);
}
}
private static class FieldComparator implements Comparator {
public int compare(Object arg0, Object arg1) {
return ((Field)arg0).getName().compareTo(((Field)arg1).getName());
}
}
private static class ConstructorComparator implements Comparator {
public int compare(Object arg0, Object arg1) {
// can ignore the name...
return ((Method)arg0).getSignature().compareTo(((Method)arg1).getSignature());
}
}
private static class MethodComparator implements Comparator {
public int compare(Object arg0, Object arg1) {
Method m1 = (Method)arg0;
Method m2 = (Method)arg1;
int result = m1.getName().compareTo(m2.getName());
if (result!=0) return result;
return m1.getSignature().compareTo(m2.getSignature());
}
}
}

+ 10
- 0
docs/devGuideDB/ajc.xml View File

@@ -431,6 +431,16 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term>-XaddSerialVersionUID</term>
<listitem><para>Causes the compiler to calculate and add
the SerialVersionUID field to any type implementing
Serializable that is affected by an aspect. The field
is calculated based on the class before weaving has
taken place.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-Xreweavable[:compress]</term>
<listitem><para>(Experimental - deprecated as now default)

BIN
lib/bcel/bcel-src.zip View File


BIN
lib/bcel/bcel.jar View File


+ 2
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java View File

@@ -533,6 +533,8 @@ public class BuildArgParser extends Main {
buildConfig.setGenerateJavadocsInModelMode(true);
} else if (arg.equals("-Xdev:NoAtAspectJProcessing")) {
buildConfig.setNoAtAspectJAnnotationProcessing(true);
} else if (arg.equals("-XaddSerialVersionUID")) {
buildConfig.setAddSerialVerUID(true);
} else if (arg.equals("-Xdev:Pinpoint")) {
buildConfig.setXdevPinpointMode(true);
} else if (arg.equals("-Xjoinpoints:arrayconstruction")) {

+ 2
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties View File

@@ -132,6 +132,8 @@ xoption.usage = {0} non-standard options:\n\
\t by AspectJ.\n\
\t-XserializableAspects allows aspects to implement serializable\n\
\t-XterminateAfterCompilation compile classes then terminate before weaving\n\
\t-XaddSerialVersionUID calculates and adds the serialVersionUID to any\n\
\t serializable type woven by an aspect\n\
\t-Xajruntimelevel:<level> allows code to be generated that targets\n\
\t a 1.2 or a 1.5 level AspectJ runtime (default 1.5)\n\
\t-XhasMember allow hasmethod() and hasfield type patterns in\n\

+ 8
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java View File

@@ -388,6 +388,7 @@ public class AjBuildConfig {
}
setOutxmlName(global.getOutxmlName());
setXconfigurationInfo(global.getXconfigurationInfo());
setAddSerialVerUID(global.isAddSerialVerUID());
}

void join(Collection local, Collection global) {
@@ -523,6 +524,13 @@ public class AjBuildConfig {
public boolean isXdevPinpoint() {
return options.xdevPinpoint;
}
public void setAddSerialVerUID(boolean b) {
options.addSerialVerUID = b;
}
public boolean isAddSerialVerUID() {
return options.addSerialVerUID;
}

public boolean isXNotReweavable() {

+ 1
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java View File

@@ -633,6 +633,7 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
cp.addAll(buildConfig.getClasspath());
BcelWorld bcelWorld = new BcelWorld(cp, handler, null);
bcelWorld.setBehaveInJava5Way(buildConfig.getBehaveInJava5Way());
bcelWorld.setAddSerialVerUID(buildConfig.isAddSerialVerUID());
bcelWorld.performExtraConfiguration(buildConfig.getXconfigurationInfo());
bcelWorld.setTargetAspectjRuntimeLevel(buildConfig.getTargetAspectjRuntimeLevel());
bcelWorld.setOptionalJoinpoints(buildConfig.getXJoinpoints());

+ 1
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java View File

@@ -80,6 +80,7 @@ public class AjCompilerOptions extends CompilerOptions {
public String targetAspectjRuntimeLevel = Constants.RUNTIME_LEVEL_DEFAULT;
public String xConfigurationInfo;
public boolean addSerialVerUID = false;
// these next four not exposed by IDEs
public boolean generateModel = false;

+ 5
- 0
tests/features151/serialveruid/AnAspect.java View File

@@ -0,0 +1,5 @@
aspect AnAspect {
before(): staticinitialization(BigHorribleClass) {
}
}

+ 19
- 0
tests/features151/serialveruid/Basic.java View File

@@ -0,0 +1,19 @@
import java.io.Serializable;
import java.lang.reflect.Field;

public class Basic implements Serializable {
public static void main(String[] args) {
try {
Basic b = (Basic)Basic.class.newInstance();
Field f = Basic.class.getDeclaredField("serialVersionUID");
long l = f.getLong(b);
System.err.println("SerialVersionUID is "+l);
} catch (Exception e) {
System.err.println("Problem: "+e.toString());
}
}
}

aspect X {
before(): staticinitialization(Basic) {}
}

+ 28
- 0
tests/features151/serialveruid/BigHorribleClass.java View File

@@ -0,0 +1,28 @@
import java.io.Serializable;
import java.lang.reflect.Field;

public class BigHorribleClass implements Serializable,Comparable {
public static void main(String[] args) {
try {
BigHorribleClass b = (BigHorribleClass)BigHorribleClass.class.newInstance();
Field f = BigHorribleClass.class.getDeclaredField("serialVersionUID");
long l = f.getLong(b);
System.err.println("SerialVersionUID is "+l);
} catch (Exception e) {
System.err.println("Problem: "+e.toString());
}
}
public int anInt;
public static boolean aBoolean = false;
public long foo = 376;
public void m() {}
public int compareTo(Object o) { return 0;}
public String m2(boolean b,long l, String s) { return "";}
public static transient short fo2 = 3;
}

+ 1
- 0
tests/src/org/aspectj/systemtest/ajc151/AllTestsAspectJ151.java View File

@@ -21,6 +21,7 @@ public class AllTestsAspectJ151 {
suite.addTest(Ajc151Tests.suite());
suite.addTest(NewarrayJoinpointTests.suite());
suite.addTest(AtAroundTests.suite());
suite.addTest(SerialVersionUIDTests.suite());
//$JUnit-END$
return suite;
}

+ 35
- 0
tests/src/org/aspectj/systemtest/ajc151/SerialVersionUIDTests.java View File

@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (c) 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andy Clement - initial implementation
*******************************************************************************/
package org.aspectj.systemtest.ajc151;

import java.io.File;

import junit.framework.Test;

import org.aspectj.testing.XMLBasedAjcTestCase;


public class SerialVersionUIDTests extends XMLBasedAjcTestCase {

public void testTheBasics() { runTest("basic"); }
public void testTheBasicsWithLint() { runTest("basic - lint"); }
public void testHorrible() { runTest("horrible"); }
//
public static Test suite() {
return XMLBasedAjcTestCase.loadSuite(SerialVersionUIDTests.class);
}

protected File getSpecFile() {
return new File("../tests/src/org/aspectj/systemtest/ajc151/serialversionuid.xml");
}
}

+ 37
- 0
tests/src/org/aspectj/systemtest/ajc151/serialversionuid.xml View File

@@ -0,0 +1,37 @@
<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd"[]>

<!-- AspectJ v1.5.1 Tests -->
<suite>
<ajc-test dir="features151/serialveruid" title="basic">
<compile files="Basic.java" options="-1.5 -XaddSerialVersionUID"/>
<run class="Basic">
<stderr>
<line text="SerialVersionUID is 7052682057082172300"/>
</stderr>
</run>
</ajc-test>
<ajc-test dir="features151/serialveruid" title="basic - lint">
<compile files="Basic.java" options="-1.5 -XaddSerialVersionUID -Xlint:warning">
<message kind="warning" text="calculated SerialVersionUID for type Basic"/>
</compile>
<run class="Basic">
<stderr>
<line text="SerialVersionUID is 7052682057082172300"/>
</stderr>
</run>
</ajc-test>
<ajc-test dir="features151/serialveruid" title="horrible">
<compile files="BigHorribleClass.java,AnAspect.java" options="-1.5 -XaddSerialVersionUID -Xlint:warning">
<message kind="warning" text="calculated SerialVersionUID for type BigHorribleClass"/>
</compile>
<run class="BigHorribleClass">
<stderr>
<line text="SerialVersionUID is 6512414869923012873"/>
</stderr>
</run>
</ajc-test>
</suite>

+ 3
- 0
weaver/src/org/aspectj/weaver/Lint.java View File

@@ -114,6 +114,9 @@ public class Lint {
public final Kind swallowedExceptionInCatchBlock =
new Kind("swallowedExceptionInCatchBlock","exception swallowed in catch block");
public final Kind calculatingSerialVersionUID =
new Kind("calculatingSerialVersionUID","calculated SerialVersionUID for type {0} to be {1}");
// there are a lot of messages in the cant find type family - I'm defining an umbrella lint warning that
// allows a user to control their severity (for e.g. ltw or binary weaving)
public final Kind cantFindType =

+ 6
- 0
weaver/src/org/aspectj/weaver/World.java View File

@@ -90,6 +90,9 @@ public abstract class World implements Dump.INode {
/** Flags for the new joinpoints that are 'optional' */
private boolean optionalJoinpoint_ArrayConstruction = false; // Command line flag: "arrayconstruction"
private boolean addSerialVerUID = false;
private Properties extraConfiguration = null;
// Records whether ASM is around ... so we might use it for delegates
@@ -1061,6 +1064,9 @@ public abstract class World implements Dump.INode {
workInProgress1.remove(baseClass);
}

public void setAddSerialVerUID(boolean b) { addSerialVerUID=b;}
public boolean isAddSerialVerUID() { return addSerialVerUID;}
public void flush() {
// System.err.println("BEFORE FLUSHING");
// System.err.println(typeMap.toString());

+ 1
- 0
weaver/src/org/aspectj/weaver/XlintDefault.properties View File

@@ -40,3 +40,4 @@ cantFindTypeAffectingJPMatch = warning

unorderedAdviceAtShadow=ignore
swallowedExceptionInCatchBlock=warning
calculatingSerialVersionUID=ignore

+ 34
- 3
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java View File

@@ -39,6 +39,7 @@ import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.Signature;
import org.aspectj.apache.bcel.classfile.Unknown;
import org.aspectj.apache.bcel.classfile.annotation.Annotation;
import org.aspectj.apache.bcel.generic.BasicType;
import org.aspectj.apache.bcel.generic.ClassGen;
import org.aspectj.apache.bcel.generic.ConstantPoolGen;
import org.aspectj.apache.bcel.generic.FieldGen;
@@ -69,6 +70,7 @@ import org.aspectj.weaver.WeaverStateInfo;
import org.aspectj.weaver.World;
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;


/**
* Lazy lazy lazy.
* We don't unpack the underlying class unless necessary. Things
@@ -99,6 +101,8 @@ public final class LazyClassGen {
private boolean isSerializable = false;
private boolean hasSerialVersionUIDField = false;
private boolean serialVersionUIDRequiresInitialization = false;
private long calculatedSerialVersionUID;
private boolean hasClinit = false;
// ---
@@ -279,12 +283,28 @@ public final class LazyClassGen {
hasClinit = true;
}
}
// Do we need to calculate an SUID and add it?
if (!hasSerialVersionUIDField && world.isAddSerialVerUID()) {
calculatedSerialVersionUID = myGen.getSUID();
Field fg = new FieldGen(
Constants.ACC_PRIVATE|Constants.ACC_FINAL|Constants.ACC_STATIC,
BasicType.LONG,"serialVersionUID",getConstantPoolGen()).getField();
addField(fg);
hasSerialVersionUIDField=true;
serialVersionUIDRequiresInitialization=true;
// warn about what we've done?
if (world.getLint().calculatingSerialVersionUID.isEnabled())
world.getLint().calculatingSerialVersionUID.signal(
new String[]{getClassName(),Long.toString(calculatedSerialVersionUID)+"L"},null,null);
}
}

Method[] methods = myGen.getMethods();
for (int i = 0; i < methods.length; i++) {
addMethodGen(new LazyMethodGen(methods[i], this));
}
}

public static boolean hasSerialVersionUIDField (ResolvedType type) {
@@ -935,10 +955,21 @@ public final class LazyClassGen {
// }

private void addAjcInitializers() {
if (tjpFields.size() == 0) return;
if (tjpFields.size() == 0 && !serialVersionUIDRequiresInitialization) return;
InstructionList il = null;
if (tjpFields.size()>0) {
il = initializeAllTjps();
}
if (serialVersionUIDRequiresInitialization) {
if (il==null) {
il= new InstructionList();
}
il.append(new PUSH(getConstantPoolGen(),calculatedSerialVersionUID));
il.append(getFactory().createFieldAccess(getClassName(), "serialVersionUID", BasicType.LONG, Constants.PUTSTATIC));
}
InstructionList il = initializeAllTjps();

getStaticInitializer().getBody().insert(il);
}

Loading…
Cancel
Save