Сокрытие информации в Groovy (с использованием замыканий "соглашения об именах")

Это следует из моей неудачной попытки найти ответ на этот вопрос с 2014 года.

Мне не ясно, могут ли на самом деле в Groovy быть какие-то методы использования замыканий, в частности, для сокрытия информации. Все, что я могу сказать, это то, что если информация о таких методах существует, то это точная иллюстрация "сокрытия информации": я не могу ее найти!

Но если мне не удастся понять, что я сейчас понимаю, так это то, что когда-либо предпринималась абсолютно нулевая попытка скрыть информацию (или сделать вид, как в Java - с учетом методов отражения). Похоже, что это из-за дизайна, но также из-за требований динамического характера Groovy. Кажется, например, что @CompileStaticУпоминается в упомянутом вопросе, больше о проверке типов, чем что-либо еще.

Но в Python, например, существует соглашение (я полагаю, все еще используется), чтобы "поля, которые должны рассматриваться как частные", начинались с двойного подчеркивания. Я никогда не слышал, чтобы кто-то говорил об этом в связи с Groovy.

Разве это не сокрытие информации и не инкапсуляция или, по крайней мере, соглашения, поощряющие дисциплинированное использование "интимного состояния" объектов, хорошие вещи? Любые специалисты Groovy хотят прокомментировать?

потом

Даггетт дал ответ, который интересен в некоторых отношениях, но не совсем то, что я имел в виду. Учти это:

class Main {
    static main( args ) {
        def sm = new SecurityManager()
        System.setSecurityManager( sm )
        println new Bob().doSomethingProtected()
    }
}


class Bob {
    public doSomethingPublic() {
        "public"
    }
    private doSomethingPrivate() {
        "private"
    }
    protected doSomethingProtected() {
        "protected"
    }
}

... какой бы из них Bob методы называется это пройдет с SecurityManager не установлен, но не работает с ним. Также не имеет значения, в какой упаковке он находится. Не имеет значения, Bob находится в подпакете (например), с @PackageScope: это только если Main.main дано @CompileStatic что это поможет (см. ссылочный вопрос). Мне также не ясно, что именно вы можете сделать с SecurityManager установить таким образом: возможно ли обеспечить соблюдение private или же protected (или пакет-приват) каким-то образом? На данный момент я просто не знаю, и мне придется расследовать.

Что касается другого предложения, оно интригует, но на самом деле не отрицает "видимость", как было предложено. Вам также необходимо включить следующий метод в классе A:

def getI() {
    throw new Exception()
}

После этого, да, видимость запрещена для любого другого класса, будь то в том же пакете или нет, а также эти "частные" элементы даже не видны другим объектам того же класса (! - в отличие от Java). В этом смысле это действительно обеспечивает очень драконовскую конфиденциальность. Но для меня это тоже немного взломать. Я не совсем ясно об этом GroovyObjectSupport класс или что он делает, и должен будет исследовать это. Наконец, нет смысла давать этим полям private модификатор. Как я уже сказал, ЕДИНСТВЕННАЯ функция private в Groovy - отрицать видимость этих полей для подклассов класса Даггетта A Вот.

Имея только абсолютный выбор между супер-драконовским и хакерским "частным" или "неограниченно публичным", явно представляет собой значительное "обнищание" выбора видимости по сравнению с Java, где у вас есть не только protected но также пакетно-приватный (тема, да, да, да, конечно, использование отражения...), и где private поля видны другим объектам того же класса.

2 ответа

Менеджер по безопасности

не запускайте следующий код из GroovyConsole, только из заводной командной строки.

def sm = new SecurityManager()
System.setSecurityManager(sm)
//without previous lines the following code will run successfully
println new ByteArrayOutputStream().buf

это бросит следующее исключение

Caught: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:109)
        at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:131)
Caused by: java.lang.ExceptionInInitializerError
        at groovy.ui.GroovyMain.run(GroovyMain.java:397)
        at groovy.ui.GroovyMain.process(GroovyMain.java:370)
        at groovy.ui.GroovyMain.processArgs(GroovyMain.java:129)
        at groovy.ui.GroovyMain.main(GroovyMain.java:109)
        ... 6 more
Caused by: java.security.AccessControlException: access denied ("java.util.logging.LoggingPermission" "control")
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
        at java.security.AccessController.checkPermission(AccessController.java:884)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
        at java.util.logging.LogManager.checkPermission(LogManager.java:1586)
        at java.util.logging.Logger.checkPermission(Logger.java:422)
        at java.util.logging.Logger.setUseParentHandlers(Logger.java:1799)
        at org.codehaus.groovy.runtime.StackTraceUtils.<clinit>(StackTraceUtils.java:57)
        ... 10 more

контролировать доступ с getProperty & setProperty

class A extends GroovyObjectSupport{
    private int i=555
    private int j=666
    def f(){
        println "i=$i j=$j"
    }
    Object getProperty(String name){
        if(name in ['i'])throw new Exception("Access to property `$name` is denied")
        return super.getProperty(name)
    }
}
def a=new A()
a.f()
println "a.j = ${a.j}"
println "a.i = ${a.i}"

это позволит получить доступ к члену j но не члену i вне класса.

выход:

i=555 j=666
a.j = 666
Exception thrown

java.lang.Exception: Access to property `i` is denied
  ...

Я создал расширение компилятора, которое позволяет выборочно или глобально применять проверки времени компиляции на предмет нарушения инкапсуляции. Кроме того, вы можете применить строгую проверку типов и проверку неизменности во время компиляции.https://github.com/stansonhealth/ast-framework

Пример:

                  package com.stansonhealth.ast.encapsulate
            import com.stansonhealth.ast.encapsulate.Encapsulate

            @Encapsulate
            class TestEncapsulationFixture {
                private int i
            }
            
            class TestEncapsulation {
                void foo(TestEncapsulationFixture fixture) {
                    fixture.i++
                    fixture[i]++
                    fixture.i = 0
                    def x = fixture.i
                }
            }

Вывод компилятора:

      startup failed:
TestEncapsulation: 14: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 14, column 21.
                       fixture.i++
                       ^

TestEncapsulation: 15: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 15, column 21.
                       fixture[i]++
                       ^

TestEncapsulation: 16: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 16, column 21.
                       fixture.i = 0
                       ^

TestEncapsulation: 17: Field or property "i" not accessible for class = com.stansonhealth.ast.encapsulate.TestEncapsulationFixture
 @ line 17, column 29.
                       def x = fixture.i
                               ^

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