ぽらろいどの日記

新しい知見を得たり、得られた知見を記録したり共有したりする場を予定しています。

Groovyでprivateを機能させる(デフォルトコンストラクタを隠す)ために--compile-staticを使う

問題

  1. Groovyでprivateを正しく機能させたいが、普通に実行すると、privateなフィールドでもアクセスできてしまう
  2. Groovyで引数なしのコンストラクタを無効にしたいが、普通に実行すると、引数なしでコンストラクタが起動できてしまう

解決

  • groovy --compile-static x.groovy で実行し、--compile-staticオプションを有効にする
  • 引数なしのコンストラクタは、privateで修飾して外部から隠す

(まあそうですよね、という回答ではある……)

おまけ

privateを実現する方法が、他にあるか?

  • 問題2は、問題1に依存
    • privateが機能すれば、引数なしのコンストラクタをprivateにして非公開に出来る
    • 引数有りのコンストラクタを用意しても、MapConstructorしか排除できない
  • 従って、privateを機能させる方法があればよい(と書いて思ったが、そういえば一応引数なしは@NullCheckで防御できた)

検討1: getter / setter を排除すれば、完全なprivateにできないか?

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
test.groovy: 14: The method setProperty should be public as it implements the corresponding method from interface groovy.lang.GroovyObject
package groovy.lang;

public interface GroovyObject {
    Object invokeMethod(String name, Object args);
    Object getProperty(String propertyName);
    void setProperty(String propertyName, Object newValue);
    MetaClass getMetaClass();
    void setMetaClass(MetaClass metaClass);
}

検討2: getter / setter を明示的に指定して、その中でエラーを送出すればprivate風にできないか?

  • すべてのgetter / setterに設定するのは、労力が掛かる
private setName(String str){
  throw new IllegalAccessError("can't access private field name")
}

検討3: getProperty() / setProperty()内で一律に制限すれば、private風にできないか?

def getProperty(String name) {
  if(Modifier.isPrivate(this.getClass().getDeclaredField(name).getModifiers())) {
    if(Modifier.isPrivate(this.getClass().getDeclaredMethod("get${name.capitalize()}").getModifiers())) {
      throw new IllegalAccessError("can't access private field $name")
    }
  }
  metaClass.getProperty(this, name)
}

検討4: privateにしたいものはtraitsで定義し、それをクラスで継承すればprivateを実現できるか?

  • privateにするためだけに分けるのは無駄な手間で、構造もおかしくなる

結論

  • Javaが常に静的型付けなのに対して、Groovyは動的・静的(風)を--compile-staticオプションにより任意で選べるようにしている
  • この任意性に反して、privateへのアクセス禁止を常に強制し、加えて引数なしのコンストラクタを無効にするなら、面倒な設定が必要になるのは容易に想像可能
  • 必須でないかぎり素直に用意された方法に従うのが、初めから無難だったのだろう……(あるいは、初めから別の静的型付けの言語を利用する)