Java Недопустимые модификаторы классов Код исключения 0x209 - PullRequest
3 голосов
/ 02 декабря 2009

У меня проблема с устаревшей кодовой базой. Я хочу начать компиляцию в формате класса 1.6, но есть одна проблема, которая проявляется только тогда, когда я пытаюсь запустить скомпилированный код. Я получаю следующее исключение:

java.lang.ClassFormatError: Недопустимые модификаторы класса в классе FooBar 0x209

Поиск в Google не раскрывает много деталей. Согласно this проблема может быть связана с несоответствием между интерфейсом и модификаторами реализации. И, конечно, должно быть какое-то новое ограничение, которого не было в 1.5.

Проблема огромного класса и имеет много внутренних классов и внутренних внутренних классов, поэтому проблему трудно отследить (я уверен, что это один из внутренних классов). Излишне говорить, что в классе также нет тестов, поэтому его изменение требует особой осторожности и трудоемко.

Итак, есть ли у кого-нибудь точная информация о 0x209 - что конкретно означает код?

РЕДАКТИРОВАТЬ:

Благодаря тому, что Арне подтолкнул нас в правильном направлении, мы смогли отследить проблему и обойти ее. Причина не совсем ясна, но теперь мы можем ее избежать.

Мы используем древний пакет Doug Lea util.concurrent в определенных областях, потому что некоторые компоненты работают в средах, которые предоставляют только Java 1.1 (да, это смеяться вполне нормально, я не против)

Этот же код (с использованием одновременных утилит) также используется в качестве небольшого компонента другого связанного программного обеспечения. Поскольку в коде Дуга использовались некоторые функции 1.2, мы также были вынуждены изменить некоторые части util.concurrent, чтобы сделать его 1.1 совместимым с пакетом коллекций Sun 1.1 с обратным портом (больше не могу найти ссылку на них). Каким-то образом это вызвало специфическое поведение компиляции Eclipse, которое происходит, когда мы меняем формат класса на Java 1.6. Это минимальный код, который вызывает проблему:

EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
import com.sun.java.util.collections.Map;

public class FooBar
{
    public static void main(String[] args) {
        Map.Entry e = (Map.Entry)(new ConcurrentHashMap().entrySet().iterator().next());
    }
}

После того, как вы скомпилируете это с Eclipse (с компиляцией, установленной на 1.6, 1.5 работает нормально) и попытаетесь загрузить класс из 1.6 JRE Sun, проблема возникает. Обходной путь: вместо циклического перебора записей мы перебираем ключи и получаем значения внутри циклов с ключами.

Наши настройки настолько экзотичны, что неудивительно, что никто больше не сталкивался с этим. Я наконец-то проверил наши скрипты сборки, и вот, у ant-script есть 1.6 source и target-settings. Так что, очевидно, это специфично для Eclipse.

EDIT2:

Я посмотрел ближе к сообщению об ошибке Солнца, которое я связал здесь. Эта проблема также связана с com.sun.java.util.collections.Map.Entry. И это произошло с Sun Javac. Интересно.

1 Ответ

8 голосов
/ 02 декабря 2009

Код - это не код, а внутреннее представление модификаторов классов в байтовом коде вашего файла классов.

Существует восемь различных флагов, которые можно установить.

ACC_PUBLIC (0x0001)
ACC_FINAL (0x0010)
ACC_SUPER (0x0020)
ACC_INTERFACE (0x0200)
ACC_ABSTRACT (0x0400)
ACC_SYNTHETIC (0x1000)
ACC_ANNOTATION (0x2000)
ACC_ENUM (0x4000)

Например, открытый финальный класс будет иметь байты модификатора 0x0011, открытый абстрактный класс 0x0401.

Ваш случай 0x209 (или лучше: 0x0209) является недопустимым модификатором. Он выглядит как интерфейс (0x0200), но часть 0x0009 не является частью спецификации. Я предполагаю, что это ошибка компилятора.

Может быть, следующий код поможет изолировать проблему. Он читает модификаторы класса из файла класса и проверяет, подходит ли модификатор. Если это не так, он печатает имя файла и не действует !!! Возможно, вы можете использовать этот инструмент в своих файлах классов, чтобы изолировать класс, вызывающий ошибку.

import java.io.*;

public class Main {

 public static void main(String[] args) throws Exception {
  String path = "D:/Arne/workspaces/IDEDeluxe/TestBytecode/bin/";
  String[] fileNames = { "Main.class" };
  for(String fileName : fileNames)
   traceFile(path, fileName);
 }

 private static void traceFile(String path, String fileName) throws FileNotFoundException, IOException {
  DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(path + fileName)));
  trace(fileName, readClassAccessFlags(stream));
  stream.close();
 }

 private static int readClassAccessFlags(DataInputStream stream) throws IOException {
  skipHeader(stream);
  skipConstantPool(stream);
  return stream.readUnsignedShort();
 }

 private static void skipHeader(DataInputStream stream) throws IOException {
  stream.readInt();
  stream.readUnsignedShort();
  stream.readUnsignedShort();
 }

 private static void skipConstantPool(DataInputStream stream) throws IOException {
  int constantPoolCount = stream.readUnsignedShort();
  for(int n = 1; n < constantPoolCount; n++) {
   int tag = stream.readUnsignedByte();
   switch(tag) {
   case 7:
    stream.readUnsignedShort();
    break;
   case 9:
   case 10:
   case 11:
    stream.readUnsignedShort();
    stream.readUnsignedShort();
    break;
   case 8:
    stream.readUnsignedShort();
    break;
   case 3:
   case 4:
    stream.readInt();
    break;
   case 5:
   case 6:
    stream.readInt();
    stream.readInt();
    break;
   case 12:
    stream.readUnsignedShort();
    stream.readUnsignedShort();
    break;
   case 1:
    stream.readUTF();
    break;
   }
  }
 }

 private static void trace(String fileName, int flags) {
  System.out.print(fileName + ": " + Integer.toHexString(flags) + " - ");
  if((flags & 0x0001) != 0)
   flags -= 0x0001;
  if((flags & 0x0010) != 0)
   flags -= 0x0010;
  if((flags & 0x0020) != 0)
   flags -= 0x0020;
  if((flags & 0x0200) != 0)
   flags -= 0x0200;
  if((flags & 0x0400) != 0)
   flags -= 0x0400;
  if((flags & 0x1000) != 0)
   flags -= 0x1000;
  if((flags & 0x2000) != 0)
   flags -= 0x2000;
  if((flags & 0x4000) != 0)
   flags -= 0x4000;
  if(flags == 0)
   System.out.println("OK!");
  else
   System.out.println("INVALID!!!");
 }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...