Как сделать Groovy-метод действительно защищенным
Попытка сделать метод в заводной protected
:
package com.foo
class Foo {
protected def getSomething(){
}
}
Это не работает, так как Groovy по умолчанию делает почти все видимым, поэтому я попытался использовать @PackageScope
package com.foo
import groovy.transform.PackageScope
@PacakgeScope
class Foo {
def getSomething(){
}
}
Такого рода работает, но только если звонящий использует @CompileStatic
...
package com.bar
class Bar {
@CompileStatic
static void main(args){
def f = new Foo()
println f.getSomething()
}
Вышеуказанные броски IllegalAccessError
Классно, но без @CompileStatic
ошибка не генерируется; не так приятно Я не могу заставить пользователей компилировать статически, так есть ли альтернатива protected
методы?
Из Groovy Документация
Защищенный в Groovy имеет то же значение, что и защищенный в Java, то есть вы можете иметь друзей в одном пакете, а производные классы также могут видеть защищенные члены.
Хорошо, если protected
имеет то же значение в Groovy, но не применяется как таковое, не разрушает ли это значение? Может быть, я что-то упустил,
2 ответа
Краткий ответ: Groovy не требует проверки видимости.
Более длинный ответ Защищенный имеет значение в Java, что вы наверняка знаете. Я упоминаю это только для заинтересованного читателя: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html
Нельзя сказать, что Groovy не устанавливает тот же модификатор. Таким образом, как видно из Java, член будет защищен так же, как и в самой Java. Более того, Groovy не выполняет проверку видимости во время выполнения (или во время компиляции) и может даже использовать отражение для форсирования доступности. Groovy должен сделать это, потому что в целом в Groovy класс, обращающийся к члену, является одним из времени выполнения. Это означает, что Groovy придется эмулировать проверки видимости во время выполнения, но для этого требуется какой-то "источник вызова", но он не всегда доступен в Groovy из-за отсутствия в протоколе метаобъекта возможности его правильной передачи.
Использование @CompileStatic вещи разные. Здесь прямой доступ к члену производится. Только он должен был уже потерпеть неудачу при компиляции и не потерпеть неудачу во время выполнения с IllegalAccessError.
Это довольно царапает голову. Я только что выполнил поиск по "скрытой информации". Там почти ничего нет!
Там могут быть методы, связанные с замыканиями для получения сокрытия информации в Groovy. Но я просто провел несколько экспериментов и нашел способ, надеюсь, навязать @CompileStatic
которые могут быть полезны. Он включает в себя использование внутреннего класса в сочетании с подклассами из abstract
класса, и выдает исключение, если предпринята недопустимая попытка обойти фабричный метод. На самом деле это был настоящий взлом.
Более того, при ближайшем рассмотрении я обнаружил, что даже это не сработало.
Единственный способ, который я нашел до сих пор, - это такой хакерский взлом, что мне стыдно даже упоминать об этом: техника, включающая проверку трассировки стека.
О возвращении с Groovy In Action 2nd Ed. мне ясно, что на самом деле @CompileStatic
гораздо больше о применении проверки типов, чем о скрытии информации: он описан таким образом, что выглядит как более мощная версия аннотации @TypeChecked
,
В Python есть соглашение, которое, я полагаю, до сих пор используется, дает специальным соглашениям об именах для полей, которые должны рассматриваться как "частные", а именно, чтобы имя начиналось с двойного подчеркивания. Но я ничего такого не видел в Groovy.
Блох в своей превосходной книге " Эффективная Java" приводит множество веских причин, по которым сокрытие информации очень важно. Конечно, к настоящему времени хорошо известно, что даже в Java все это ненадежно и может быть взломано методами отражения. Но я хотел бы услышать от Groovy uber-geek их мнение по вопросу, поднятому вашим вопросом...