5

Vì vậy, ngay bây giờ, tôi có một máy chủ đang chạy với ObjectInputStreamObjectOutputStream.Gửi một lớp Chưa xác định trên ổ cắm? (Object..Stream in Java)

Sự cố tôi gặp phải là tôi có một lớp tùy chỉnh (ẩn danh) mở rộng java.lang.Date mà tôi đang cố gắng gửi cho khách hàng và sau đó biên dịch.

Vì vậy, tôi không bao giờ định nghĩa lớp ở phía máy khách, nhưng tôi muốn biên dịch lớp theo chương trình. Tôi đã thử nhiều phương pháp khác nhau, nhưng mỗi lần tôi nhận được ClassNotFoundException vì lớp học không ở phía khách hàng ban đầu.

Class<?> dateClass = (Class<?>) in.readObject(); //This is where the CNF Exception occurs 
Compiler.compileClass(dateClass); 

Trả lời

7

Cơ chế tuần tự Java giả định các lớp được biết đến JVM deserializing, nó không gửi định nghĩa lớp. Đặc biệt, khi bạn tuần tự hóa một đối tượng Class, bạn không gửi mã byte cho lớp đó mà chỉ hướng dẫn VM nhận để tra cứu đối tượng Class cho một lớp có tên cụ thể.

Cũng lưu ý rằng đối tượng Class đại diện cho một lớp được xác định trong JVM, nghĩa là bytecode của lớp đã được tải. Sẽ rất ít khi cố gắng biên dịch sang lớp để tạo ra bytecode sau khi tải lớp này.

Vì vậy, chúng tôi cần bằng cách nào đó có được định nghĩa lớp cho khách hàng. Cách tiếp cận dễ nhất là làm điều này giống như bất kỳ lớp nào khác mà máy khách cần (bằng cách đóng gói nó trong tệp jar của ứng dụng khách, hoặc bất cứ điều gì có nghĩa là bạn sử dụng để cài đặt chương trình máy khách). Nếu không thể, bạn có thể tải định nghĩa lớp trên mạng, ví dụ bằng cách sử dụng một URLClassLoader hoặc bạn có thể gửi tệp lớp thông qua luồng tuần tự hóa và khi nhận nó trên ứng dụng khách ClassLoader.defineClass để tải lớp.

PS: Vấn đề này hoàn toàn độc lập cho dù lớp học có được đặt tên hay không. Các mã kiểm tra dưới đây cho thấy rằng đối tượng của các lớp nặc danh có thể được serialized và deserialized tốt (nếu VM nhận có định nghĩa lớp):

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { 
     Serializable payload = new Serializable() { 
      @Override 
      public String toString() { 
       return "hello from the anonymous class"; 
      } 
     }; 
     oos.writeObject(payload); 
     oos.writeObject(payload.getClass()); 
    } 

    try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { 
     System.out.println(in.readObject()); 
     System.out.println(in.readObject()); 
    } 
+1

Đây là một câu trả lời tốt hơn nhiều so với lời nói bậy bạ súc tích về nonymising, mặc dù đó là một từ buồn cười. Giống như "jelly" và "wibble". Vì vậy, nếu chúng ta bỏ phiếu cho những từ hài hước thì câu trả lời này sẽ kéo dài trong những phiếu bầu đó ngay bây giờ. – davidfrancis

+0

Đó là những gì tôi đã suy nghĩ ban đầu. Gửi tệp cho lớp qua mạng sau đó chỉ cần cài đặt nó vào DIR khi nó đến đó. Cảm ơn bạn đã bảo đảm: D – Avogadro

+0

Bạn nên gửi lớp anon qua trình nạp lớp mạng - ví dụ: sử dụng nạp lớp rmi là cách java gốc để làm việc này – davidfrancis

Các vấn đề liên quan