2015-08-27 2 views
1

ФоновыхNoSuchMethodException - тип возвращаемого значения изменилось - Хочет принять оба типа

У меня есть библиотека общин, что я должен обновить. Эта библиотека commons имеет стороннюю зависимость (jgroups), которая значительно изменилась в новых версиях. С помощью транзитивных зависимостей иногда требуется более новая версия групп, и это нарушает библиотеку общих ресурсов. Мне нужно обновить некоторые классы для совместимости с более новыми версиями, поддерживая обратную совместимость.

Проблема

JGroups обеспечивает View класс, который имеет метод getMembers(). В старой версии (2.10.0) этот метод возвращает Vector<Address>, а в более новой версии (3.2.7) это возвращает List<Address>. Любая реализация java.util.Collection будет работать для меня, но проблема в том, что я получаю NoSuchMethodException. Как я понимаю, найденный метод getMembers() имеет прежний тип возврата Vector<Address> (на основе зависимости JGroups в библиотеке commons), но я перетаскиваю новую версию JGroups и что класс View ожидает List<Address>, возвращенный из метода getMembers().

StackTrace

Я получаю следующее сообщение об ошибке при запуске моего приложения в Eclipse.

Caused by: java.lang.NoSuchMethodError: org.jgroups.View.getMembers()Ljava/util/Vector; 
    at com.mycompany.commons.messaging.events.impl.distributed.JGroupsEventDistributionProvider$JGroupsEventReceiver.viewAccepted(JGroupsEventDistributionProvider.java:136) ~[classes/:na] 
    at org.jgroups.JChannel.invokeCallback(JChannel.java:752) ~[jgroups-3.2.7.Final.jar:3.2.7.Final] 
    at org.jgroups.JChannel.up(JChannel.java:710) ~[jgroups-3.2.7.Final.jar:3.2.7.Final] 
    at org.jgroups.stack.ProtocolStack.up(ProtocolStack.java:1020) ~[jgroups-3.2.7.Final.jar:3.2.7.Final] 
    at org.jgroups.protocols.pbcast.FLUSH.up(FLUSH.java:466) ~[jgroups-3.2.7.Final.jar:3.2.7.Final] 
.... 

Где он ломает

Collection<Address> viewMembers = view.getMembers(); 

Вопрос

Можно ли поддерживать обе версии, даже если они отличаются от других реализаций Collection? Как я могу обработать этот сценарий, когда я не знаю тип возвращаемого метода до времени выполнения?

Примечание:

Я попытался исключить старую версию JGroups, что засасывается путем добавления исключения в моем Maven ПОМ. Это не сработало.

<dependency> 
     <groupId>com.mycompany.commons</groupId> 
     <artifactId>mycompany-commons-event-distributed-jgroups</artifactId> 
     <!-- Note: JGroups dependency is provided by infinispan --> 
     <version>1.0.2-SNAPSHOT</version> 
     <type>jar</type> 
     <scope>compile</scope> 
     <exclusions> 
      <exclusion> 
       <groupId>org.jgroups</groupId> 
       <artifactId>jgroups</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 
+1

Больше обходного решения, чем решение - но как насчет предоставления собственного метода полезности и вместо этого вместо 'getMembersRaw()'. Это возвращает базовый массив, поэтому вы захотите скопировать эти значения в коллекцию, чтобы предотвратить непреднамеренную модификацию. http://www.jgroups.org/javadoc/org/jgroups/View.html#getMembersRaw-- – deyur

+0

@deyur, спасибо за предложение. К сожалению, getMembersRaw() недоступен в моих версиях JGroups, 2.10.0 или 3.2.7 –

+1

Как насчет использования отражения? Поле View.members - это вектор

в 2.10.x и массив Address [] в 3.x. Вы можете получить доступ к полю View.members и - в зависимости от его типа - вернуть всех членов в виде набора адресов. Не красиво, но должно работать ... –

ответ

1

Как об использовании отражения? Поле View.members - это вектор в 2.10.x и массив Address [] в 3.x. Вы можете получить доступ к полю View.members и - в зависимости от его типа - вернуть всех членов в виде набора адресов. Не красиво, но должно работать.

1

Если вы используете «обычную java» для рамки приложения, я думаю, что вам вообще не повезло.

Без использования какой-либо модульной структуры, такой как OSGI, у вас есть только один пул классов, и каждый класс, загруженный в ваш путь к классу, переходит в этот пул. Это означает, что вы не можете одновременно иметь несколько версий одного JAR или одного и того же класса в JVM.

Кроме того, вы должны поддерживать несколько версий одного и того же JAR, потому что у вас есть по крайней мере две части кода, скомпилированные каждый против различных версий: один ожидает возвращаемое значение Vector, а другой List, так что даже если вы могли бы изолировать нежелательный элемент от вашей среды сборки, созданный против него код не будет ссылаться на правильный двоичный файл, и вы продолжите получать исключение во время выполнения, которое вы видите.

К сожалению, вы упомянули, что это «библиотека», а не только одно приложение, что может затруднить применение решения. С верхней части моей головы, я вижу эти варианты для вас двигаться вперед, ни один из которых являются тривиальными и некоторые из них не может быть возможным:

  1. понизить ваш код, как необходимо только иметь одну версию JGroups во всех зависимостей цепи
  2. перепроектировать приложение для использования OSGI или аналогичную структуру, которая поддерживает несколько версий одной и той же библиотеки, поэтому цепочки зависимостей могут расходиться
  3. перепроектировать приложение и разобщают его на несколько, что при каждом запуске в своей собственной виртуальной машины Java, сообщающийся с розетками или любые другие средства

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

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

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