📄 serialversionuidadder.java
字号:
/*
* Gets class field information for step 4 of the alogrithm. Also determines
* if the class already has a SVUID.
*/
public FieldVisitor visitField(final int access,
final String name,
final String desc,
final String signature,
final Object value) {
if ( this.computeSVUID ) {
if ( name.equals( "serialVersionUID" ) ) {
// since the class already has SVUID, we won't be computing it.
this.computeSVUID = false;
this.hasSVUID = true;
}
/*
* Remember field for SVUID computation For field modifiers, only
* the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
* ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
* computing serialVersionUID values.
*/
final int mods = access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
if ( ((access & Opcodes.ACC_PRIVATE) == 0) || ((access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) ) {
this.svuidFields.add( new Item( name,
mods,
desc ) );
}
}
return super.visitField( access,
name,
desc,
signature,
value );
}
/*
* Add the SVUID if class doesn't have one
*/
public void visitEnd() {
// compute SVUID and add it to the class
if ( this.computeSVUID && !this.hasSVUID ) {
try {
this.cv.visitField( Opcodes.ACC_FINAL + Opcodes.ACC_STATIC,
"serialVersionUID",
"J",
null,
new Long( computeSVUID() ) );
} catch ( final Throwable e ) {
throw new RuntimeException( "Error while computing SVUID for " + this.name,
e );
}
}
super.visitEnd();
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Returns the value of SVUID if the class doesn't have one already. Please
* note that 0 is returned if the class already has SVUID, thus use
* <code>isHasSVUID</code> to determine if the class already had an SVUID.
*
* @return Returns the serial version UID
* @throws IOException
* @throws NoSuchAlgorithmException
*/
protected long computeSVUID() throws IOException,
NoSuchAlgorithmException {
if ( this.hasSVUID ) {
return 0;
}
ByteArrayOutputStream bos = null;
DataOutputStream dos = null;
long svuid = 0;
try {
bos = new ByteArrayOutputStream();
dos = new DataOutputStream( bos );
/*
* 1. The class name written using UTF encoding.
*/
dos.writeUTF( this.name.replace( '/',
'.' ) );
/*
* 2. The class modifiers written as a 32-bit integer.
*/
dos.writeInt( this.access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT) );
/*
* 3. The name of each interface sorted by name written using UTF
* encoding.
*/
Arrays.sort( this.interfaces );
for ( int i = 0; i < this.interfaces.length; i++ ) {
dos.writeUTF( this.interfaces[i].replace( '/',
'.' ) );
}
/*
* 4. For each field of the class sorted by field name (except
* private static and private transient fields):
*
* 1. The name of the field in UTF encoding. 2. The modifiers of the
* field written as a 32-bit integer. 3. The descriptor of the field
* in UTF encoding
*
* Note that field signatutes are not dot separated. Method and
* constructor signatures are dot separated. Go figure...
*/
writeItems( this.svuidFields,
dos,
false );
/*
* 5. If a class initializer exists, write out the following: 1. The
* name of the method, <clinit>, in UTF encoding. 2. The modifier of
* the method, java.lang.reflect.Modifier.STATIC, written as a
* 32-bit integer. 3. The descriptor of the method, ()V, in UTF
* encoding.
*/
if ( this.hasStaticInitializer ) {
dos.writeUTF( "<clinit>" );
dos.writeInt( Opcodes.ACC_STATIC );
dos.writeUTF( "()V" );
} // if..
/*
* 6. For each non-private constructor sorted by method name and
* signature: 1. The name of the method, <init>, in UTF encoding. 2.
* The modifiers of the method written as a 32-bit integer. 3. The
* descriptor of the method in UTF encoding.
*/
writeItems( this.svuidConstructors,
dos,
true );
/*
* 7. For each non-private method sorted by method name and
* signature: 1. The name of the method in UTF encoding. 2. The
* modifiers of the method written as a 32-bit integer. 3. The
* descriptor of the method in UTF encoding.
*/
writeItems( this.svuidMethods,
dos,
true );
dos.flush();
/*
* 8. The SHA-1 algorithm is executed on the stream of bytes
* produced by DataOutputStream and produces five 32-bit values
* sha[0..4].
*/
final MessageDigest md = MessageDigest.getInstance( "SHA" );
/*
* 9. The hash value is assembled from the first and second 32-bit
* values of the SHA-1 message digest. If the result of the message
* digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
* five int values named sha, the hash value would be computed as
* follows:
*
* long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF) <<
* 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
* 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
* 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
* 56;
*/
final byte[] hashBytes = md.digest( bos.toByteArray() );
for ( int i = Math.min( hashBytes.length,
8 ) - 1; i >= 0; i-- ) {
svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
}
} finally {
// close the stream (if open)
if ( dos != null ) {
dos.close();
}
}
return svuid;
}
/**
* Sorts the items in the collection and writes it to the data output stream
*
* @param itemCollection collection of items
* @param dos a <code>DataOutputStream</code> value
* @param dotted a <code>boolean</code> value
* @exception IOException if an error occurs
*/
private void writeItems(final Collection itemCollection,
final DataOutputStream dos,
final boolean dotted) throws IOException {
final int size = itemCollection.size();
final Item items[] = (Item[]) itemCollection.toArray( new Item[size] );
Arrays.sort( items );
for ( int i = 0; i < size; i++ ) {
dos.writeUTF( items[i].name );
dos.writeInt( items[i].access );
dos.writeUTF( dotted ? items[i].desc.replace( '/',
'.' ) : items[i].desc );
}
}
// ------------------------------------------------------------------------
// Inner classes
// ------------------------------------------------------------------------
static class Item
implements
Comparable {
String name;
int access;
String desc;
Item(final String name,
final int access,
final String desc) {
this.name = name;
this.access = access;
this.desc = desc;
}
public int compareTo(final Object o) {
final Item other = (Item) o;
int retVal = this.name.compareTo( other.name );
if ( retVal == 0 ) {
retVal = this.desc.compareTo( other.desc );
}
return retVal;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -