]> source.dussan.org Git - aspectj.git/commitdiff
101411: -XaddSerialVersionUID POST_MEMORY_CHANGES
authoraclement <aclement>
Thu, 9 Mar 2006 17:24:19 +0000 (17:24 +0000)
committeraclement <aclement>
Thu, 9 Mar 2006 17:24:19 +0000 (17:24 +0000)
19 files changed:
bcel-builder/src/org/aspectj/apache/bcel/generic/ClassGen.java
docs/devGuideDB/ajc.xml
lib/bcel/bcel-src.zip
lib/bcel/bcel.jar
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java
tests/features151/serialveruid/AnAspect.java [new file with mode: 0644]
tests/features151/serialveruid/Basic.java [new file with mode: 0644]
tests/features151/serialveruid/BigHorribleClass.java [new file with mode: 0644]
tests/src/org/aspectj/systemtest/ajc151/AllTestsAspectJ151.java
tests/src/org/aspectj/systemtest/ajc151/SerialVersionUIDTests.java [new file with mode: 0644]
tests/src/org/aspectj/systemtest/ajc151/serialversionuid.xml [new file with mode: 0644]
weaver/src/org/aspectj/weaver/Lint.java
weaver/src/org/aspectj/weaver/World.java
weaver/src/org/aspectj/weaver/XlintDefault.properties
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java

index bec436bf6267be01f6446302137a53055d83734f..9e21b271ed9c09c05141863067eaf97277363e35 100644 (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());
+               }
+  }
 }
index 109bac74128d13b4cfbeb838a9fb4ff3f7aa6ff8..30ca3b9019e6f4b174f5fcf9b87087cd1542bcdb 100644 (file)
         </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) 
index 68ddd550243db65b8c2f0859c3d4f377f0b50f1c..770d77312575e75813c53ddd9738fa8d1620e058 100644 (file)
Binary files a/lib/bcel/bcel-src.zip and b/lib/bcel/bcel-src.zip differ
index e96515cb91f9d55c748fb8c16d0451810a007923..d6237720c7cd26762b2b3ad9ba81321d094e4553 100644 (file)
Binary files a/lib/bcel/bcel.jar and b/lib/bcel/bcel.jar differ
index fccb824ee17ede4d7327829c829bb72a8c3de95d..f2749997d457507814f07c52485f2423427dd716 100644 (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")) {
index 16111cb0fa58533c30fa91c411e28740663f0dc9..16e6e4eafe26f35542500fedfd34c72e8b61336a 100644 (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\
index c616cfeb0d8cac72edc3cb97d54c66243709a65e..472180fd6d857a7a491a521a4c05345ee4378fb9 100644 (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() {
index d2a7e88c890dca1331200a1c49ae7ba7d8d5a442..f46dbd4d4e5c0cb9dd39e52969be67cccc2cfe8c 100644 (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());
index 54a271c276855aea7808961a5b5fd83804850c6c..6407b6da761457208e1bfec36791ffd4dd25a548 100644 (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;
diff --git a/tests/features151/serialveruid/AnAspect.java b/tests/features151/serialveruid/AnAspect.java
new file mode 100644 (file)
index 0000000..eff8137
--- /dev/null
@@ -0,0 +1,5 @@
+aspect AnAspect {
+       before(): staticinitialization(BigHorribleClass) {
+               
+       }
+}
\ No newline at end of file
diff --git a/tests/features151/serialveruid/Basic.java b/tests/features151/serialveruid/Basic.java
new file mode 100644 (file)
index 0000000..f2093d5
--- /dev/null
@@ -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) {}
+}
\ No newline at end of file
diff --git a/tests/features151/serialveruid/BigHorribleClass.java b/tests/features151/serialveruid/BigHorribleClass.java
new file mode 100644 (file)
index 0000000..7668307
--- /dev/null
@@ -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;
+  
+}
\ No newline at end of file
index a3929851a6232b3777570e461b189b5e9aef22d8..8f64f29d81e6f4c6a42a3057b060a7d09d61b1dd 100644 (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;
        }
diff --git a/tests/src/org/aspectj/systemtest/ajc151/SerialVersionUIDTests.java b/tests/src/org/aspectj/systemtest/ajc151/SerialVersionUIDTests.java
new file mode 100644 (file)
index 0000000..fc0c0d2
--- /dev/null
@@ -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");
+  }
+       
+}
diff --git a/tests/src/org/aspectj/systemtest/ajc151/serialversionuid.xml b/tests/src/org/aspectj/systemtest/ajc151/serialversionuid.xml
new file mode 100644 (file)
index 0000000..c18adae
--- /dev/null
@@ -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>
\ No newline at end of file
index 2ca50ad85d302cf7dbf09bd39104adbeaf13cb6b..f2542367cc4e51d263b05898e29d8767f7d72988 100644 (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 =
index 5f9cf6d013499dddd41dffef04702efbf884c8d5..870ba7f43f6d3978979f077176ee97ad0a032f15 100644 (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());
index bef40796931382c264de5d0deba73125f42eaae7..70063a74eb14c6de7f526852473e862dab1a0d09 100644 (file)
@@ -40,3 +40,4 @@ cantFindTypeAffectingJPMatch = warning
 
 unorderedAdviceAtShadow=ignore
 swallowedExceptionInCatchBlock=warning
+calculatingSerialVersionUID=ignore
\ No newline at end of file
index 3d485ab027e965f72a46ceac35e36868e3056b78..6533ea1312d19ef0605c64b23076a5a9d5783e9d 100644 (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);
     }