📄 classversionlimiter.java
字号:
package org.compiere.tools;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;
/**
* <b>JDK 1.4 Beta 2 won't work with JBuilder</b>
* <p>
* When compiling a ".java"-file the compiler puts format version info in the
* first bytes of the resulting class file. In Merlin (JDK 1.4)
* Beta2 Sun has changed the version info of many of the JDK's class files
* to '48.0' while previous JDKs used versions up to '46.0'.
* I do not know if there actually are any differences in the class file format.
* There are almost certainly some minor changes. Unfortunately the JDK 1.4 release
* notes fail to adress this incompatibility. If anyone knows some details please e-mail me.
* The JDK tools provided with the Beta release can all deal with version '48.0' class files.
* But if you use other tools (like the Borland compiler), they will probably refuse to load the JDK's class files.
* <p>
* <b>Patch the JDK 1.4 Beta 2 release</b>
* <p>
* To be able to play around with Merlin Beta 2 using JBuilder5, I wrote a little hack,
* that patches all jar files in the JDK to a version of max. '46.0'.
* I got my current project running without noticing any problems.
* <p>
* THIS IS A HACK. IT WILL ALMOST CERTAINLY BREAK SOME CODE. USE AT YOUR OWN RISK.
* If in any part of your application you get some strange errors,
* especially related to class loading, this patch may well be the reason.
* Please E-Mail me with details about where the problems occur.
* <p>
* If your JDK's root directory isn't "D:\jdk1.4b2"
* then edit the path in the code (one of the very first lines).
* Be sure to have write access to the JDK sub-directories.
* <p>
* Run the resulting class. It will patch all class files in all jar files
* in your JDK to have a version info of '46.0' at max.
* The original jar-files will get copied to .BAK-files.
* <p>
* java -cp %COMPIERE_HOME%/lib/CServer.jar org.compiere.tools.ClassVersionLimiter
*
* @author Stephen Kelvin - with minor changes by Jorg Janke
* @see http://www.StephenKelvin.de/MerlinPatch/
* @version $Id: ClassVersionLimiter.java,v 1.3 2001/11/14 02:49:29 jjanke Exp $
*/
public class ClassVersionLimiter
{
/**
* Run it
*/
public static void main(String[] args)
{
ClassVersionLimiter classVersionLimiter = new ClassVersionLimiter("D:/j2sdk1.4b3p", 46, 0);
} // main
/** Version Key */
private long _maxAllowedVersion;
/** Log file */
private PrintWriter m_out = null;
/**
* Constructor
*/
public ClassVersionLimiter(String rootDirectory, int mainVersion, int minorVersion)
{
_maxAllowedVersion = mainVersion * 65536 + minorVersion;
// Create Log file
try
{
File logFile = new File(rootDirectory + File.separator + "patchJar.log");
m_out = new PrintWriter(new FileOutputStream(logFile), true); // autoFlush
System.out.println("Log=" + logFile.getAbsolutePath());
}
catch (Exception e)
{
System.err.println("Cannot write log");
e.printStackTrace(System.err);
System.exit(1);
}
// Change jars
File root = new File(rootDirectory);
search(root);
} // ClassVersionLimiter
/**
* Search all for all jars in a directory and recursively go through sub-directories
*/
private void search(File dir)
{
dir.listFiles (new FileFilter()
{
public boolean accept(File pathname)
{
if (pathname.getName().endsWith(".jar"))
checkJar(pathname);
if (pathname.isDirectory())
search(pathname);
return false;
}
});
} // search
/**
* Check the Jar
*/
private void checkJar(File file)
{
byte[] header = new byte[8];
long maxVersion = 0;
boolean foundClassFiles = false;
try
{
JarFile jarFile = new JarFile(file);
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements())
{
JarEntry entry = (JarEntry) entries.nextElement();
if (entry.getName().endsWith(".class"))
{
foundClassFiles = true;
InputStream stream = jarFile.getInputStream(entry);
stream.read(header);
int mainVersion = header[6] * 256 + header[7];
int minorVersion = header[4] * 256 + header[5];
long version = mainVersion * 65536 + minorVersion;
if (version > maxVersion)
maxVersion = version;
}
}
jarFile.close();
if (foundClassFiles && maxVersion > _maxAllowedVersion)
{
patchJar(file);
}
}
catch (Exception e)
{
log ("checkJar", e);
}
} // checkJar
/**
* Patch the Jar
*/
private void patchJar(File file)
{
log ("Patching " + file, null);
try
{
final int MAX_ENTRY_SIZE = 1024 * 1024; // 1 MB
byte[] classBytes = new byte[MAX_ENTRY_SIZE];
File newFile = new File(file.getAbsolutePath() + ".NEW");
CRC32 crc32 = new CRC32();
JarFile oldJarFile = new JarFile(file);
Manifest manifest = oldJarFile.getManifest();
FileOutputStream outputStream = new FileOutputStream(newFile);
JarOutputStream jarOutput = new JarOutputStream(outputStream, manifest);
Enumeration entries = oldJarFile.entries();
while (entries.hasMoreElements())
{
JarEntry oldEntry = (JarEntry) entries.nextElement();
JarEntry newEntry = (JarEntry) oldEntry.clone();
System.out.print("."); // indicate progress, don't log
if (oldEntry.getName().equals("META-INF/MANIFEST.MF"))
continue;
// copy into classBytes
InputStream in = oldJarFile.getInputStream(oldEntry);
int totalLen = 0;
int readLen = 0;
do
{
totalLen += readLen;
readLen = in.read(classBytes, totalLen, MAX_ENTRY_SIZE - totalLen);
} while(readLen > 0);
if (totalLen == MAX_ENTRY_SIZE)
{
log ("ERROR= patchJAR: MAX_ENTRY_SIZE too small - " + MAX_ENTRY_SIZE, null);
return;
}
if (totalLen > 0 && oldEntry.getName().endsWith(".class"))
{
int mainVersion = classBytes[6] * 256 + classBytes[7];
int minorVersion = classBytes[4] * 256 + classBytes[5];
long version = mainVersion * 65536 + minorVersion;
// we need to patch this class file
if (version > _maxAllowedVersion)
{
log (" - " + oldEntry.getName(), null);
mainVersion = (int) _maxAllowedVersion / 65536;
minorVersion = (int) _maxAllowedVersion % 65536;
classBytes[4] = (byte) (minorVersion / 256);
classBytes[5] = (byte) (minorVersion % 256);
classBytes[6] = (byte) (mainVersion / 256);
classBytes[7] = (byte) (mainVersion % 256);
crc32.reset();
crc32.update(classBytes, 0, totalLen);
newEntry.setCrc(crc32.getValue());
// The compressed size can differ if the uncompressed data is changed. -1 means unknown.
newEntry.setCompressedSize(-1);
}
}
jarOutput.putNextEntry(newEntry);
if (totalLen > 0)
jarOutput.write(classBytes, 0, totalLen);
jarOutput.closeEntry();
}
jarOutput.close();
outputStream.close();
oldJarFile.close();
// done with entries
log ("", null);
//
File bakFile = new File(file.getAbsolutePath() + ".BAK");
if (!file.renameTo(bakFile))
{
log ("ERROR= Cannot rename " + file + " to " + bakFile + ". EXITING.", null);
System.exit(99);
}
if(!newFile.renameTo(file))
{
log ("ERROR= Cannot rename " + newFile + " to " + file + ". EXITING.", null);
System.exit(99);
}
}
catch (Exception e)
{
log ("patchJar", e);
}
} // patchJar
/**
* Log entries in file
*/
private void log (String message, Exception e)
{
if (e == null)
{
System.out.println(message);
m_out.println(message);
}
else
{
System.err.print("ERROR= ");
System.err.println(message);
e.printStackTrace(System.err);
//
m_out.print("ERROR= ");
m_out.println(message);
e.printStackTrace(m_out);
}
} // log
} // ClassVersionLimiter
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -