2016-11-08 3 views
1

Я хочу, чтобы проверить, если два значения имеет один и тот же класс:Сравнения классов до повышения CGLIB

x.getClass.equals(y.getClass) 

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

Очевидным решением является поиск $$EnhancerByCGLIB$$... в имени класса, его удаление и сравнение остальных частей имен классов (и загрузчиков классов). Есть ли лучшая альтернатива?

ответ

2

cglib позволяет пользователю установить NamingStrategy, что делает замену метки EnhancerByCGLIB ненадежной, так как класс может быть назван произвольно.

Самый надежный способ идентификации класса cglib - проверить наличие поля CGLIB$BOUND, которое жестко закодировано в библиотеке, так что имя не может измениться. Если такое поле существует в классе, вам необходимо проверить:

  1. Имеются любые интерфейсы. Если существует хотя бы один интерфейс, расширенный класс может быть этим интерфейсом. (Возможно, вы найдете интерфейс cglib Factory, который вы должны игнорировать.)
  2. Существует класс супер, который не является java.lang.Object. Даже если интерфейс расширен, существует, очевидно, суперкласс.

В качестве приближения для алгоритма обнаружения, можно поэтому использовать:

static Class<?> original(Class<?> type) { 
    try { 
    type.getDeclaredField("CGLIB$BOUND"); 
    if (type.getSuperclass() != Object.class) { 
     return type.getSuperclass(); 
    } 
    for (Class<?> iFace : type.getInterfaces()) { 
     if (iFace != Factory.class) { 
     return iFace; 
     } 
    } 
    return Object.class; 
    } catch (NoSuchFieldException ignored) { 
    return type; 
    } 
} 

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

Смежные вопросы