問題
- Groovyでprivateを正しく機能させたいが、普通に実行すると、privateなフィールドでもアクセスできてしまう
- Groovyで引数なしのコンストラクタを無効にしたいが、普通に実行すると、引数なしでコンストラクタが起動できてしまう
解決
groovy --compile-static x.groovy
で実行し、--compile-staticオプションを有効にする- 引数なしのコンストラクタは、privateで修飾して外部から隠す
(まあそうですよね、という回答ではある……)
おまけ
privateを実現する方法が、他にあるか?
- 問題2は、問題1に依存
- 従って、privateを機能させる方法があればよい(と書いて思ったが、そういえば一応引数なしは@NullCheckで防御できた)
検討1: getter / setter を排除すれば、完全なprivateにできないか?
- フィールドにアクセス修飾子をつけると、クラス内にgetter / setterは設定されない
- 実際にgetter / setterを要求するインターフェイスを用意し、それが満たされないことによって確認できる
- が、get / setPropertyが外部からの処理に対して応答し、結局アクセスは可能なままである
- 実際にアクセス時にはget / setProperty()が動作するので、getter / setterの有無はあまり関係ない
- なお、このsetPropertyはpublicにできない
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風にできないか?
- リフレクションを用いつつ、groovyのgetProperty() / setProperty()内で一律に制限できる
- 例えば、以下の例のように、逐一調べてエラーを送出する
- しかし、やはり面倒で、private / protected ...で処理を更に追加しなければならない
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にするためだけに分けるのは無駄な手間で、構造もおかしくなる