Как разделить личные данные пакета между двумя пакетами в Java?

У меня есть 2 пакета Java, A и B. Предположим, что некоторые классы в пакете B хотят использовать некоторые классы в пакете A, однако, когда разработчик приходит и разрабатывает пакет C (или, скажем, приложение C), он/она будет использовать мой пакет B, но я не хочу, чтобы он/она мог использовать классы в A, которые использует B. Другими словами, я хочу, чтобы мои классы в пакете А были закрытыми для пакета, чтобы они были скрыты от разработчика приложения. Однако я действительно хочу, чтобы мой собственный пакет B имел доступ к тем классам, которые являются частными для пакета. Можно ли это сделать на Java? Мне просто нужно стиснуть зубы и сделать классы общедоступными и просто надеяться, что пользователь не попытается их использовать? Или мне нужно реплицировать классы, которые находятся в A внутри B?

Я бы предпочел что-то не хакерское (т.е. я не хочу использовать отражение). Помощь?


person fatfreddyscat    schedule 12.06.2012    source источник
comment
Если пакет B может что-то делать с пакетом классов A, то ничто не мешает пакету C делать то же самое с пакетом классов A. Однако можно запретить пакету C получать экземпляр класса в пакете A, который член класса в пакете B (если не задействовано отражение).   -  person nhahtdh    schedule 12.06.2012
comment
Если вы хотите безопасности, не кодируйте поверх интерпретатора?   -  person starbolin    schedule 12.06.2012
comment
звучит так, как будто пакеты A и B действительно должны быть в одном пакете или что необходима какая-то фабрика, которая возвращает частную реализацию.   -  person David    schedule 12.06.2012
comment
@nhahtdh -› не могли бы вы объяснить, как можно, как вы говорите, предотвратить получение пакетом C экземпляра класса в пакете A, который является членом класса в пакете B?   -  person fatfreddyscat    schedule 12.06.2012
comment
@ Дэвид - › не могли бы вы объяснить, как создать фабрику, которая возвращает частную реализацию?   -  person fatfreddyscat    schedule 12.06.2012
comment
@fatfreddyscat: Просто убедитесь, что член защищен, без модификатора или закрытый, и убедитесь, что вы не возвращаете его экземпляр ни одним из методов (позвольте классам в одном пакете обращаться к нему напрямую без модификатора или защищен).   -  person nhahtdh    schedule 13.06.2012
comment
@nhahtdh -› извините; Я неправильно понял ваш первоначальный комментарий. Я пропустил то, что это член класса в пакете B. Да, я уже знаю, как это работает (на самом деле это был не мой вопрос). Спасибо, в любом случае!   -  person fatfreddyscat    schedule 13.06.2012
comment
ОБНОВЛЕНИЕ У меня есть очень странное решение -› поскольку пакет C должен иметь возможность получить доступ к методам в общедоступных классах пакета A, а также пакета B, и поскольку есть некоторые методы (в пакете -private class) в пакете A, к которому B должен иметь доступ, я собираюсь сделать один из методов, доступных для публичного просмотра из A, методом varargs. Пакет B вызовет этот метод с «секретным кодом», встроенным в varargs; пакет А «расшифрует» этот секретный код и вызовет соответствующий метод. Разработчик приложения не будет знать, что такое секретные коды :-)   -  person fatfreddyscat    schedule 13.06.2012
comment
Я приветствую любые комментарии к моему решению супер-хакджоба.... ??!   -  person fatfreddyscat    schedule 13.06.2012
comment
@fatfreddyscat: Это работает, но не является хорошим решением для SE.   -  person nhahtdh    schedule 13.06.2012
comment
Я полностью согласен. Однако можете ли вы (или кто-либо) предложить лучшее решение?   -  person fatfreddyscat    schedule 13.06.2012


Ответы (2)


Вы можете сделать это с помощью JDK 8 и его Проект Jigsaw. Вы можете ознакомиться с Кратким руководством по началу работы с Project Jigsaw.

К сожалению, Jigsaw является частью JDK8 и еще не полностью готов. Ожидается, что он не будет завершен до января 2013 г. и не будет выпущен до середины 2013 года.

Однако вы уже можете скомпилировать свои классы с помощью предварительной версии JDK 8 и воплотить свои идеи в жизнь.

В этом случае вашу проблему можно решить, разделив ваше приложение на независимые модули. Вы можете сделать что-то вроде:

module foo {
    exports foo;
    permits bar;
    permits baz;
}

Здесь модуль foo может потребоваться только модулям с именами bar или baz. Зависимость модуля с другим именем от foo не будет разрешаться во время компиляции, установки или выполнения. Если оговорки о разрешениях отсутствуют, то таких ограничений нет.

Не уверен, что альтернативные фреймворки, такие как OSGI, реализации которых можно найти в Apache Felix и Eclipse Equinox предлагает некоторую функциональность для реализации этих уровней инкапсуляции. Вполне вероятно, что вы захотите немного разобраться в этом.

Проблема с OSGi без существования Jigsaw заключается в том, что любые правила, применяемые платформой, могут быть нарушены Однако после размышления, как только Jigsaw будет готов к публичному использованию, эти правила будут применяться самой Java, как вы читали выше, во время компиляции, во время выполнения и во время установки.

person Edwin Dalorzo    schedule 12.06.2012
comment
Спасибо за хороший ответ (я проголосовал за него). К сожалению, я ориентируюсь на Android и JDK 6... :-/ Любые другие мысли о том, что я могу сделать? - person fatfreddyscat; 12.06.2012
comment
@fatfreddyscat OSGI, вероятно, ваш лучший вариант, но реализовать его тоже будет непросто. - person Edwin Dalorzo; 12.06.2012
comment
Обратите внимание, что Project Jigsaw не попал в Java 8, теперь он предназначен для Java 9. - person Jesper; 02.07.2015

Вы можете сделать это с OSGi. Android и JDK 6 в качестве цели в этом случае не являются проблемой, существуют платформы OSGi, работающие на Android -> например. см. сервер mBedded для Android. Скачать бесплатную некоммерческую версию можно по ссылке.

У вас есть несколько вариантов, как это сделать в OSGi, в зависимости от того, чего вы хотите достичь.

Вариант 1 (рекомендуемый): Вы можете поместить пакеты А и Б в один и тот же бандл АВ, а в манифесте этого бандла экспортировать только пакет Б с помощью Export-Package. Пакет/приложение C или любое другое «пользовательское» приложение может импортировать пакет B и использовать его. И он не может использовать и даже не видит пакет А, потому что он внутренний для связки АВ. Вам не нужны никакие специальные объявления или зависимости на уровне Java; это будет работать с ЛЮБОЙ версией Jva, потому что модульность и отдельные пространства пакетов являются частью основ OSGi и не зависят от последней версии Java или чего-то еще.

Вариант 2. Если по какой-то причине вы хотите, чтобы пакеты A и B были разделены на разные пакеты, вы можете иметь их таким образом, что вы будете экспортировать и импортировать пакеты в манифесте, а затем контролировать, какой пакет имеет право импортировать какой пакет с помощью разрешений. (см. службы разрешений OSGi и условных разрешений). Однако реализовать это сложнее.

Вариант 3. Вы также можете поместить пакет A в пакет Fragment и разрешить ему присоединяться к пакету, содержащему B. Таким образом, B будет иметь доступ к пакету A, но в то же время вы сможете обновить пакет A отдельно. во время выполнения, если хотите. Поскольку пакеты во фрагментах рассматриваются как частные для пакета узла (в данном случае узел — это пакет, содержащий пакет B), пакет C не увидит A. Он увидит только то, что экспортируется пакетом B.

Поскольку вы не очень хорошо знакомы с OSGi, я рекомендую начать с варианта 1, а затем, при необходимости, вы можете обновить свой подход до варианта 3, если хотите.

@Edwin Dalorzo: Это определенно неправда, что правила в OSGi могут быть нарушены отражением. Пакеты имеют отдельные загрузчики классов в OSGi. Вы можете размышлять о Bundle C столько же, сколько и о классах A, и единственное, что вы получите, - это исключение ClassNotFound - поверьте мне, я видел это достаточно раз;)

person pooh    schedule 14.06.2012
comment
Спасибо за подробный ответ!! В моем случае пакету C потребуется доступ как к пакету A, так и к пакету B; просто я хочу, чтобы пакет B мог получить доступ к "приватным" классам пакета внутри A... Если бы Java поддерживала концепцию "друга" (как в С++), то это могло бы работать таким образом. Я думаю, что этот подход OSGi просто может сработать для меня, однако, поскольку у меня серьезные ограничения по времени, я, скорее всего, просто использую свое «решение для взлома» (см. мой комментарий «ОБНОВЛЕНИЕ» к моему исходному сообщению) ) сейчас и потом, когда у меня будет время, изучите ваш метод. Еще раз спасибо! Голосование вверх! - person fatfreddyscat; 14.06.2012
comment
Если вы хотите экспортировать только часть пакета А в варианте 1, это тоже возможно. Используйте директивы экспорта include или exclude в записи Export-Package в манифесте: include — список имен классов, разделенных запятыми, которые должны быть видны импортеру. Обратите внимание, что использование запятой в значении требует, чтобы оно было заключено в двойные кавычки. Информацию о фильтрации классов см. в разделе Фильтрация классов на стр. 50. - person pooh; 15.06.2012