Tôi thường khuyên bạn nên chuyển đổi AST @Immutable
của Groovy như một cách dễ dàng để tạo các lớp, tốt, không thay đổi. Điều này luôn hoạt động tốt với các lớp Groovy khác, nhưng ai đó gần đây đã hỏi tôi liệu tôi có thể trộn các lớp đó vào mã Java hay không. Tôi luôn luôn nghĩ rằng câu trả lời là có, nhưng tôi đánh một tiếng.Các lớp Groovy @Immutable trong Java
Nói rằng tôi có một bất biến User
lớp:
import groovy.transform.Immutable
@Immutable
class User {
int id
String name
}
Nếu tôi thử nghiệm này sử dụng một thử nghiệm JUnit viết bằng Groovy, mọi thứ hoạt động như mong đợi:
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'
}
}
tôi có thể làm tương tự với một Kiểm tra JUnit được viết bằng Java:
nhập 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
}
}
Công trình này, mặc dù có sự cố trên đường chân trời. IntelliJ 15 không thích cuộc gọi đến new User()
, tuyên bố rằng không tìm thấy hàm tạo. Điều đó cũng có nghĩa là IDE nhấn mạnh lớp màu đỏ, nghĩa là nó có lỗi biên dịch. Tuy nhiên, bài kiểm tra vẫn trôi qua, hơi lạ một chút, nhưng cũng vậy.
Nếu tôi cố gắng sử dụng trực tiếp lớp User
trong mã Java, mọi thứ bắt đầu trở nên lạ.
public class UserDemo {
public static void main(String[] args) {
User user = new User();
System.out.println(user);
}
}
Một lần nữa IntelliJ không vui, nhưng biên dịch và chạy. Kết quả là, tất cả mọi thứ:
User(0)
Đó là kỳ quặc, bởi vì mặc dù @Immutable
chuyển đổi không tạo ra một phương pháp toString
, tôi khá mong đợi nó đầu ra để hiển thị cả tài sản. Tuy nhiên, điều đó có thể là do thuộc tính name
là không, vì vậy nó không được bao gồm trong đầu ra.
Nếu tôi cố gắng sử dụng các nhà xây dựng tuple:
public class UserDemo {
public static void main(String[] args) {
User user = new User(3, "name");
System.out.println(user);
}
}
tôi nhận được
User(0, name)
như đầu ra, ít nhất là thời gian này (đôi khi nó không hoạt động ở tất cả).
Sau đó, tôi đã thêm tệp xây dựng Gradle. Nếu tôi đặt các lớp Groovy dưới src\main\groovy
và các lớp Java dưới src\main\java
(tương tự cho các bài kiểm tra nhưng sử dụng thư mục test
thay), ngay lập tức tôi nhận được một vấn đề biên soạn:
> gradle test
error: cannot find symbol
User user = new User(...)
^
tôi thường sửa chữa các vấn đề xuyên biên soạn như thế này bằng cách cố gắng sử dụng trình biên dịch Groovy cho mọi thứ. Nếu tôi đặt cả hai lớp dưới src\main\java
, không có gì thay đổi, đó không phải là một bất ngờ lớn. Nhưng nếu tôi đặt cả hai lớp dưới src\main\groovy
, sau đó tôi có được điều này trong giai đoạn 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
Huh. Lần này nó phản đối constructor tuple, bởi vì nó nghĩ rằng nó chỉ có một constructor mặc định. Tôi biết phép biến đổi thêm một giá trị mặc định, một trình xây dựng dựa trên bản đồ và một bộ tạo tuple, nhưng có lẽ chúng không được tạo ra kịp thời cho mã Java để xem chúng.
Ngẫu nhiên, nếu tôi tách Java và lớp Groovy một lần nữa, và thêm dòng sau vào Gradle tôi xây dựng:
sourceSets {
main {
java { srcDirs = []}
groovy { srcDir 'src/main/java' }
}
}
tôi nhận được lỗi tương tự. Nếu tôi không thêm khối sourceSets
, tôi sẽ gặp lỗi không tìm thấy lớp học User
từ trước đó.
Vì vậy, dòng dưới cùng là, cách chính xác để thêm một lớp học @Immutable
Groovy vào một hệ thống Java hiện có là gì? Có cách nào để có được các nhà xây dựng được tạo ra trong thời gian cho Java để xem chúng?
Tôi đã tạo bản trình bày Groovy cho các nhà phát triển Java trong nhiều năm và nói rằng bạn có thể làm điều này, chỉ để bây giờ gặp phải các vấn đề. Xin hãy giúp tôi cứu mặt bằng cách nào đó. :)
IDE có xu hướng đưa ra âm tính sai khi nói đến Groovy, đặc biệt là với các biến đổi AST. Đối với vấn đề biên dịch chéo bạn có thể thử có hai dự án riêng biệt, một java và một groovy. Nếu đây vẫn là một câu hỏi chưa được giải quyết, tôi sẽ cho nó một tiếng huýt sáo vào buổi sáng. Điều này thực sự cảm thấy như nó sẽ làm việc. – cjstehno
Hành vi có giống với '@ CompileStatic' không? – dmahapatro
'@ CompileStatic' không thay đổi bất cứ điều gì – kousen