Лучший способ изменить целочисленное поле в скомпилированном Java-классе 1.6 без источника - PullRequest
1 голос
/ 06 мая 2011

Файл класса, скомпилированный с настройками java 1.6, имеет два поля, которые мне нужно установить на более высокие значения.

private Integer days = 7;
private Integer running = 30;

к сожалению, у меня больше нет доступа к коду правильной ревизии, и владею только файлом класса.

Вот что я уже попробовал: я играл с BCEL, asm и javassist, но это совсем не тривиально.Я не смог найти подходящий редактор байт-кода (jbe выглядит очень странно, редактор классов не показывает значение объектов Integer).Средство просмотра файлов класса байт-кода Eclipse зависает при попытке сохранения.Использование шестнадцатеричного редактора для манипулирования значениями исключено, поскольку в них будет больше цифр, чем сейчас.Я также изучил javap и перекомпилировал его с помощью jasmin - что не представляется возможным.

Итак, в конечном итоге, пожалуйста, о, пожалуйста, есть ли у кого-нибудь хороший пример того, как это можно сделать любым мыслимым способом?*

Ответы [ 7 ]

2 голосов
/ 06 мая 2011

Вы можете установить их, используя отражение, как указано в предыдущем ответе.Вот пример:

public class TestSetPrivateFields extends TestCase {

    public void testSetFields() throws Exception {
        Legacy legacyObj = new Legacy();
                    // get the fields using reflection
        Field[] fields = {
                          legacyObj.getClass().getDeclaredField("days"),
                          legacyObj.getClass().getDeclaredField("running")
                          }; 
        for (Field field : fields) {
            field.setAccessible(true);
            Integer value = (Integer) field.get(legacyObj);
            // set their value
            field.set(legacyObj, value+1);
        }

        Legacy expected = new Legacy();
        assertEquals(expected.getDays()+1, legacyObj.getDays()+0);
        assertEquals(expected.getRunning()+1, legacyObj.getRunning()+0);
    }

    public static class Legacy {
        private Integer days = 7;
        private Integer running = 30;

        public Integer getDays() {return days;}
        public Integer getRunning() { return running;}
    }

}
2 голосов
/ 06 мая 2011

Вы пытались декомпилировать, редактировать, а затем перекомпилировать?Насколько я знаю, JD работает довольно хорошо.

http://java.decompiler.free.fr/

0 голосов
/ 19 июля 2011

Использование редактора байт-кода чрезвычайно просто.Либо у поля будет связанный атрибут DefaultValue, либо вы найдете в () V что-то вроде:

aload_0
bipush 7
invokestatic java/lang/Integer#valueOf (I)Ljava/lang/Integer;
putfield Blah#days Ljava/lang/Integer;

Должно быть понятно, что здесь исправить.

0 голосов
/ 06 мая 2011

Лично я бы использовал ASMifier (или схему байт-кода Eclipse) для создания java-класса, который при запуске с java -cp asm-all.jar MyAsmClass будет производить новую версию необходимого класса. Указанные значения должны быть обновлены во всех конструкторах и будут вызываться visitLdcInsn().

0 голосов
/ 06 мая 2011

Взгляните на JD-Core .Плагин для eclipse позволил мне заглянуть в какую-нибудь недокументированную библиотеку, чтобы лучше понять ее.Он не работает на всех скомпилированных Java-классах, но для меня он в значительной степени открыл все.

0 голосов
/ 06 мая 2011

Это выглядит многообещающе:

http://classeditor.sourceforge.net/

0 голосов
/ 06 мая 2011

Не могу представить, почему у вас нет источника.

Я бы не прошел через всю эту боль. Если это сложно, возможно, это признак того, что вы не должны этого делать.

Я бы предпочел использовать JAD , декомпилировать файл .class, внести изменения и продолжить.

...