Tim Tyler said:
: Graham Matthews wrote:
:> Try compiling the above code on a non OS-X platform. It will complain
:> that it can't find classes referenced in the "use_an_apple_extension"
:> bit.
: And the aforementioned stub library solves your compilation problem.
: I do it all the time.
What program do you use to make the stubs?
I know Dale wrote a program called CodeHusker to do this - are there
others?
I basically wrote that for you and never really finshed it off for public
consumption. Anybody is welcome to take what I started and run with it. I
attached the source at the end. It uses BCEL to do the job. Having gotten
more experience with BCEL, I would probably do it differently now.
I always believed that compiling against stubs ought to speed up loading
and searching rt.jar - and other large libraries people compile against.
These days it might also speed up things like code completion as well.
I'm not so convinced that it will, but am certainly interested to find out.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.i

utputStream;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.ConstantValue;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.SourceFile;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
/**
* @author kingd
* @version $Revision$ $Date$
*/
public class CodeHusker
{
private final ZipInputStream zinp;
private final ZipOutputStream zoutp;
private boolean keepResources = false;
private final InstructionList emptyInstructionList = new
InstructionList();
public CodeHusker( InputStream in, OutputStream out )
{
zinp = new ZipInputStream( in );
zoutp = new ZipOutputStream( out );
}
/**
* Sets the keepResources.
* @param keepResources The keepResources to set
*/
public void setKeepResources(boolean keepResources)
{
this.keepResources = keepResources;
}
public static void main(String[] args) throws IOException
{
InputStream in = new FileInputStream( args[0] );
OutputStream fos = new FileOutputStream( args[1] );
CodeHusker h = new CodeHusker( in, fos );
h.setKeepResources( false );
h.beginCodeRemoval();
System.out.println( "done" );
}
public void beginCodeRemoval() throws IOException
{
for( ZipEntry entry; ( entry = zinp.getNextEntry() ) != null; )
{
String name = entry.getName();
handleFile( name, zinp );
}
zinp.close();
zoutp.close();
}
private OutputStream createFile( String name ) throws IOException
{
final ZipEntry outEntry = new ZipEntry( name );
final CRC32 crc = new CRC32();
zoutp.putNextEntry( outEntry );
return new CheckedOutputStream( zoutp, crc )
{
public void close() throws IOException
{
outEntry.setCrc( crc.getValue() );
zoutp.closeEntry();
}
};
}
private void handleFile( String name, InputStream in )
throws IOException, ClassFormatError
{
if( name.endsWith( ".class" ) )
{
InputStream input = new FilterInputStream( in )
{
public void close() throws IOException
{
// ignore closes
}
};
OutputStream out = createFile( name );
handleClass( name, input, out );
}
else if( keepResources )
{
OutputStream out = createFile( name );
for( int c; ( c = in.read() ) != -1; )
{
out.write( c );
}
out.close();
}
}
private void handleClass( String name, InputStream in, OutputStream
out )
throws IOException, ClassFormatError
{
ClassParser parser = new ClassParser( in, name );
JavaClass cls = parser.parse();
ClassGen c = stripClass( cls );
c.getJavaClass().dump( out );
}
private ClassGen stripClass( JavaClass cls )
{
ConstantPoolGen origPool = new
onstantPoolGen( cls.getConstantPool() );
ClassGen c = new ClassGen( "", "", "", 0, new String[ 0 ] );
// ClassGen constructor unfortunately adds a SourceFile
// attribute by default, remove it and any other default attributes.
Attribute[] attrib = c.getAttributes();
for (int i = 0; i < attrib.length; i++)
{
Attribute attribute = attrib
;
c.removeAttribute( attribute );
}
// Removing the attribute does not remove the strings
// from the constant pool, so let's start again fresh
// with a new constant pool.
ConstantPoolGen cp = new ConstantPoolGen();
c.setConstantPool( cp );
// Since we restarted the constant pool, we need to
// set everything that would have been set in the
// constructor.
c.setClassName( cls.getClassName() );
c.setSuperclassName( cls.getSuperclassName() );
c.setAccessFlags( cls.getAccessFlags() );
c.setMajor( cls.getMajor() );
c.setMinor( cls.getMinor() );
attrib = cls.getAttributes();
for( int i = 0; i < attrib.length; i++ )
{
Attribute attribute = attrib;
if( !( attribute instanceof SourceFile ) )
{
c.addAttribute( attribute );
}
}
String[] interfaces = cls.getInterfaceNames();
for( int i = 0; i < interfaces.length; i++ )
{
c.addInterface( interfaces );
}
Field[] flds = cls.getFields();
for (int i = 0; i < flds.length; i++)
{
Field field = flds;
// Lose any private fields
if( !field.isPrivate() )
{
Attribute[] fa = field.getAttributes();
for (int j = 0; j < fa.length; j++)
{
Attribute attribute = fa[j];
if( attribute instanceof ConstantValue )
{
ConstantValue cv = (ConstantValue)attribute;
int index = cv.getConstantValueIndex();
index =
cp.addConstant( origPool.getConstant( index ), origPool );
cv.setConstantValueIndex( index );
break;
}
}
FieldGen fg = new FieldGen( field, cp );
c.addField( fg.getField() );
}
}
Method[] methods = cls.getMethods();
for (int i = 0; i < methods.length; i++)
{
Method method = methods;
String name = method.getName();
// Remove any private methods except for private constructors
if( !method.isPrivate() || "<init>".equals( name ) )
{
MethodGen mg = new MethodGen( method, cls.getClassName(),
cp );
mg.stripAttributes( true );
mg.removeCodeAttributes();
mg.setInstructionList( new InstructionList() );
c.addMethod( mg.getMethod() );
}
}
return c;
}
}