我經常推薦Groovy的@Immutable
AST轉換,它是一種簡單的方法來創建類,它是不可變的。對於其他Groovy類,這總是可以正常工作,但最近有人問我是否可以將這些類混合到Java代碼中。我一直認爲答案是肯定的,但我遇到了困難。Groovy @ Java中的不可變類
說我有一個不變的User
類:
import groovy.transform.Immutable
@Immutable
class User {
int id
String name
}
如果我測試這個使用Groovy編寫的JUnit測試,一切正常:
import org.junit.Test
class UserGroovyTest {
@Test
void testMapConstructor() {
assert new User(name: 'name', id: 3)
}
@Test
void testTupleConstructor() {
assert new User(3, 'name')
}
@Test
void testDefaultConstructor() {
assert new User()
}
@Test(expected = ReadOnlyPropertyException)
void testImmutableName() {
User u = new User(id: 3, name: 'name')
u.name = 'other'
}
}
我可以做同樣的用用Java編寫的JUnit測試:
import static org.junit.Assert。*;
import org.junit.Test;
public class UserJavaTest {
@Test
public void testDefaultCtor() {
assertNotNull(new User());
}
@Test
public void testTupleCtor() {
assertNotNull(new User(3, "name"));
}
@Test
public void testImmutableName() {
User u = new User(3, "name");
// u.setName("other") // Method not found; doesn't compile
}
}
雖然在地平線上有麻煩, IntelliJ 15不喜歡調用new User()
,聲稱沒有找到構造函數。這也意味着IDE用紅色強調該類,這意味着它有一個編譯錯誤。無論如何,測試都會通過,這有點奇怪,但這樣做。
如果我嘗試直接在Java代碼中使用User
類,事情會變得很奇怪。
public class UserDemo {
public static void main(String[] args) {
User user = new User();
System.out.println(user);
}
}
再次IntelliJ不開心,但編譯和運行。輸出是,所有的東西:
User(0)
這是奇怪的,因爲雖然@Immutable
變換不會產生toString
方法,我寧願希望它的輸出同時顯示性能。不過,這可能是因爲name
屬性爲空,所以它不包含在輸出中。
如果我嘗試使用元組構造:
public class UserDemo {
public static void main(String[] args) {
User user = new User(3, "name");
System.out.println(user);
}
}
我得到
User(0, name)
爲輸出,至少在這個時候(有時不工作在所有)。
然後我添加了一個Gradle構建文件。如果我把src\main\groovy
下,Groovy類和Java類src\main\java
(同爲測試,但使用test
文件夾代替)下,我立即得到一個編譯問題:
> gradle test
error: cannot find symbol
User user = new User(...)
^
我通常解決這樣的交叉編譯的問題通過嘗試使用Groovy編譯器來處理所有事情。如果我把這兩門課都放在src\main\java
之下,沒有什麼變化,這並不是什麼大驚喜。但是,如果我把src\main\groovy
下的兩個類,然後我在compileGroovy
階段得到這樣的:
> gradle clean test
error: constructor in class User cannot be applied to the given types;
User user = new User(3, "name");
required: no arguments
found: int,String
reason: actual and formal arguments differ in length
呵呵。這一次它反對元組構造函數,因爲它認爲它只有一個默認的構造函數。我知道這個轉換添加了一個默認的,一個基於地圖的和一個元組構造器,但也許他們沒有及時生成Java代碼來查看它們。
順便說一句,如果我再次分開Java和Groovy類,並添加以下到我的搖籃建設:
sourceSets {
main {
java { srcDirs = []}
groovy { srcDir 'src/main/java' }
}
}
我得到同樣的錯誤。如果我不添加sourceSets
塊,則會收到User
類未找到的錯誤。
因此底線是,將Groovy類添加到現有Java系統的正確方法是什麼?有沒有辦法讓Java的構造函數能夠及時生成以便看到它們?
多年來,我一直在向Java開發人員進行Groovy演示,並說您可以這樣做,但現在只會遇到問題。莫名其妙地幫助我保存臉部。 :)
當談到Groovy時,IDE傾向於給出假陰性,尤其是AST轉換。對於交叉編譯問題,你可以嘗試有兩個獨立的項目,一個是java和一個是groovy。如果這仍然是一個尚未解決的問題,我會在早上給它一個旋風。這真的覺得它應該工作。 – cjstehno
行爲與'@ CompileStatic'相同嗎? – dmahapatro
'@ CompileStatic'不會改變任何東西 – kousen