Currently I am trying to update an old project. The problem is, that in one of my sources (bungeecord) they have changed two fileds (see enum "protocol") from public final to final modifier. To make the project work again I need to access these two fields.
As a reason of this I try to "inject" the project. This works great, so the modifier changes but I am currently not able to save it to the jar file. But this is necessary.
The process of saving works perfectly for the "userconnection" (see enum below). In this case I edit a class modifier.
If you need any more Information please let me know.
When the "injection" (enum: protocol) is done and I check the modifier type of these fileds I see that there have been some changes. But when I restart the system and check the filed modifiers again before the "injection" they are as there were no changes.
public static int inject(InjectionType type) {
try{
System.out.println("Starting injection.");
System.out.println(type.getInfo());
ClassPool cp = ClassPool.getDefault();
CtClass clazz = cp.getCtClass(type.getClazz().getName());
switch (type) {
case USERCONNECTION:
int modifier = UserConnection.class.getModifiers();
if (!Modifier.isFinal(modifier) && Modifier.isPublic(modifier)) {
return -1;
}
clazz.setModifiers(Modifier.PUBLIC);
break;
case PROTOCOL:
CtField field = clazz.getField("TO_CLIENT");
field.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
field = clazz.getField("TO_SERVER");
field.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
break;
default:
return -1; //no data
}
ByteArrayOutputStream bout;
DataOutputStream out = new DataOutputStream(bout = new ByteArrayOutputStream());
clazz.getClassFile().write(out);
InputStream[] streams = { new ByteArrayInputStream(bout.toByteArray()) };
File bungee_file = new File(BungeeCord.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
updateZipFile(bungee_file, type, streams);
return 1;
}catch (Exception e){
e.printStackTrace();
}
return 0;
}
private static void updateZipFile(File zipFile, InjectionType type, InputStream[] ins) throws IOException {
File tempFile = File.createTempFile(zipFile.getName(), null);
if (!tempFile.delete()) {
System.out.println("Warn: Cant delete temp file.");
}
if (tempFile.exists()) {
System.out.println("Warn: Temp target file alredy exist!");
}
if (!zipFile.exists()) {
throw new RuntimeException("Could not rename the file " + zipFile.getAbsolutePath() + " to " + tempFile.getAbsolutePath() + " (Src. not found!)");
}
int renameOk = zipFile.renameTo(tempFile) ? 1 : 0;
if (renameOk == 0) {
tempFile = new File(zipFile.toString() + ".copy");
com.google.common.io.Files.copy(zipFile, tempFile);
renameOk = 2;
if (zipFile.delete()) {
System.out.println("Warn: Src file cant delete.");
renameOk = -1;
}
}
if (renameOk == 0) {
throw new RuntimeException("Could not rename the file " + zipFile.getAbsolutePath() + " to " + tempFile.getAbsolutePath() + " (Directory read only? (Temp:[R:" + (tempFile.canRead() ? 1 : 0) + ";W:" + (tempFile.canWrite() ? 1 : 0) + ",D:" + (tempFile.canExecute() ? 1 : 0) + "],Src:[R:" + (zipFile.canRead() ? 1 : 0) + ";W:" + (zipFile.canWrite() ? 1 : 0) + ",D:" + (zipFile.canExecute() ? 1 : 0) + "]))");
}
if (renameOk != 1) {
System.out.println("Warn: Cant create temp file. Use .copy file");
}
byte[] buf = new byte[Configuration.getLoadingBufferSize()];
System.out.println("Buffer size: " + buf.length);
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String path_name = entry.getName().replaceAll("/", "\\.");
boolean notReplace = true;
for (String f : type.getNames()) {
if (f.equals(path_name)) {
notReplace = false;
break;
}
}
if (notReplace) {
out.putNextEntry(new ZipEntry(entry.getName()));
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
zin.close();
for (int i = 0; i < type.getNames().length; i++) {
InputStream in = ins[i];
int index = type.getNames()[i].lastIndexOf('.');
out.putNextEntry(new ZipEntry(type.getNames()[i].substring(0, index).replaceAll("\\.", "/") + type.getNames()[i].substring(index)));
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.closeEntry();
in.close();
}
out.close();
tempFile.delete();
if (renameOk == -1) {
System.exit(-1);
}
}
}
@Getter
public enum InjectionType {
USERCONNECTION(UserConnection.class, new String[] {"net.md_5.bungee.UserConnection.class"}, "Set modifiers for class UserConnection.class to \"public\""),
PROTOCOL(Protocol.class, new String[] {"net.md_5.bungee.protocol.Protocol"}, "Set modifiers for class Protocol.class to \"public\"");
private Class<?> clazz;
private String[] names;
private String info;
InjectionType (Class<?> clazz, String[] names, String info) {
this.clazz = clazz;
this.names = names;
this.info = info;
}
}