Отражение: Enum является публичным, так же как и метод. Почему IlegalAccessException приходит?

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

Я получаю ниже исключения в моем коде случайно и не всегда:

ERROR CACHE-SELECT 2015-08-20 11:19:00,822 nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'table.selectQuerySuffix'. Cause: org.apache.ibatis.ognl.OgnlException: selectQuerySuffix [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class com.dclear.cmn.core.cache.CacheEnum$4 with modifiers "public"] - 

Enum определен следующим образом:

public enum CacheEnum {
    TABLE_NAME() {
        @Override
        public String getSelectQuerySuffix() {
            return "";
        }
    };

private CacheEnum() {
    //some assignment
}

public enum Schema {
    //SCHEMAS DEFINED
}
public enum SchemaName {
    // NAMES
}

public String getSelectQuerySuffix() {
    return "";
}

public enum ColumnEnum {
    //SOME VALUES

    ColumnEnum() {
    }

}

public enum CacheTableSequence {
    //SQs
}

}

'table.selectQuerySuffix' определен в файле MyBatis для добавления суффикса запроса. И во время выполнения это передается как "" (см. Переопределенный метод getSelectQuerySuffix())

Эта проблема не всегда приходит... Я читал, что

IllegalAccessException генерируется, когда приложение пытается рефлексивно создать экземпляр (отличный от массива), задать или получить поле, или вызвать метод, но исполняемый в настоящее время метод не имеет доступа к определению указанного класса, поля, метод или конструктор.

Там нет пользовательских загрузчиков классов.

Но если проблема возникла из-за того, что конструктор CacheEnum является закрытым, почему он не всегда появляется? Если нет, то в чем проблема? Что мне здесь не хватает?

1 ответ

Решение

Когда мы определяем Enum следующим образом:

public enum EnumTest {

    ONE, TWO() {
        @Override public String hello() {
            return "World";
        }
    };

    public String hello() {
        return "Hello";
    }
}

Java для ДВУХ создает анонимный класс. Я сделал разборку этого, и это выглядит так:

class snippet.EnumTest$1 extends snippet.EnumTest {
  snippet.EnumTest$1(java.lang.String, int);
  public java.lang.String hello();
}

Итак Class за TWO пакет защищен, и отражение не работает, когда мы на самом деле получаем доступ к классу TWO. Например, получить объект Enum для TWO и получить его класс. Я подозреваю, что это то, что происходит в вашем случае. Для всех случаев, когда метод не переопределяется, он работает, а для тех случаев, когда метод переопределяется, он должен выдавать исключение.

Я написал следующий тест для проверки.

public class EmumReflect {

    public static void main(String[] args) throws Exception {
        f1();
        f2();
    }

    public static void f1() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException,
            InvocationTargetException {
        Class<?> forName = Class.forName("snippet.EnumTest");
        Object fOne = forName.getField("ONE").get(null);
        Object fTwo = forName.getField("TWO").get(null);
        Method method = forName.getMethod("hello");
        System.out.println(method.invoke(fOne));
        System.out.println(method.invoke(fTwo));
    }

    public static void f2() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException,
            InvocationTargetException {
        Class<?> forNamex = Class.forName("snippet.EnumTest");
        Object fTwo = forNamex.getField("TWO").get(null);
        Class<?> forName = fTwo.getClass();
        Method method = forName.getMethod("hello");
        System.out.println(method.invoke(fTwo));
    }
}

Если вы храните оба файла классов EnumTest и EnumReflect в одном пакете, вы не получите никаких исключений. Но если вы храните их в разных пакетах, f2() выдает то же исключение, которое вы получаете.

Другие вопросы по тегам