17

Chúng tôi có một dự án Java. Chúng tôi kích hoạt các cờ -Xlint (bật cảnh báo) và -Werror (xử lý cảnh báo là lỗi) cho javac, để đảm bảo mã của chúng tôi không bị cảnh báo. Gần đây chúng tôi quyết định từ chối một lớp học. Vấn đề là trong một số trường hợp, @SuppressWarnings("deprecation") sẽ không ngăn chặn cảnh báo không dùng nữa, dẫn đến lỗi xây dựng. Dưới đây là danh sách các trường hợp sử dụng mà tôi đã gặp phải:Làm thế nào để tránh cảnh báo không dùng nữa khi @SuppressWarnings ("không dùng nữa") không hoạt động?

  1. Nhập vào các lớp không được chấp nhận khác.
  2. Nhập trong các lớp không được chấp nhận khác.
  3. Cấp độ gốc.
  4. Thông số loại. Ví dụ

    @SuppressWarnings("deprecation") 
    public class Foo extends Bar<DeprecatedClass> 
    { ... } 
    

    Tuy nhiên, điều này không có cảnh báo ngay cả khi không đàn áp:

    @Deprecated 
    public class DeprecatedClass extends Bar<DeprecatedClass> 
    { ... } 
    

AFAIK, không có cú pháp cho nhập khẩu chú thích, vì vậy đối với trường hợp 1 và 2 giải pháp của chúng tôi là hoặc nhập * hoặc tránh nhập. Đối với trường hợp 3 và 4, cả Java 6 và 7 đều không chặn cảnh báo. Java 8 sẽ triệt tiêu chính xác nó (có thể một lỗi đã được sửa). Cho đến nay không có giải pháp cho việc này.

Thật không may, chúng tôi phải hỗ trợ Java 6, 7 và 8 tại thời điểm này. Có cách nào để giải quyết vấn đề không? Nó là một khối đường cho sự phát triển Java API của chúng tôi.

PHỤ LỤC

Nhiều người hỏi tại sao chúng ta vẫn sử dụng lớp phản đối trong codebase của chúng ta. Lý do là dự án là một thư viện, hỗ trợ nhiều khách hàng khác nhau. Khi giới thiệu API thay thế mới, trước tiên chúng tôi phải từ chối API cũ của chúng tôi, hãy giữ nó trong mã nguồn của chúng tôi, chờ tất cả khách hàng di chuyển rồi xóa nó. Có ba trường hợp sử dụng chung:

  • Chúng tôi không dùng lớp FooBar, nơi Foo kéo dài Bar. Đây là trường hợp 2 và 3 trong câu hỏi của tôi.
  • Chúng tôi không dùng nữa lớp FooBar, trong đó Foo kéo dài Collection<Bar>. Đây là trường hợp 2 và 4.
  • Chúng tôi phải giữ tất cả mã kiểm tra cho lớp FooBar. Mã thử nghiệm nhập khẩu các lớp này. Đây là trường hợp 1.

Tại sao phải kiểm tra? Đừng quên rằng nếu một lỗi nghiêm trọng (ví dụ: rò rỉ bộ nhớ, sự cố bảo mật) được phát hiện và khách hàng không thể dễ dàng di chuyển sang phiên bản mới, chúng tôi vẫn cần cung cấp sửa lỗi cho API cũ. Và tất cả các thay đổi phải được kiểm tra.

Tôi cảm thấy tình hình của chúng ta nên khá phổ biến trong phát triển thư viện phần mềm và phát triển API. Đáng ngạc nhiên là phải mất Java thời gian dài (cho đến Java 8) để sửa lỗi.

+2

Có thể không có nhiều tùy chọn. Bạn có thể thay đổi quá trình xây dựng của bạn để không có '-Werror' trừ khi target == 8, hoặc loại trừ cảnh báo không dùng nữa vì điều đó dường như bị hỏng trong 6 và 7. Hoặc bạn không thực hiện phản đối tiêu chuẩn (imo một thay thế xấu): Bỏ qua ngừng sử dụng và xóa lớp xấu ngay lập tức, "không dùng nữa" bằng cách đặt ghi chú trên web/javadoc hoặc trong trường hợp tác phẩm đó cũng không dùng nữa mọi lớp sử dụng nó làm tham số kiểu ngay cả khi nó sẽ ở lại trong trường hợp lớp không dùng nữa biến mất. Http://stackoverflow.com/a/20909204/995891 liên quan đến 1) & 2) – zapl

+0

Tôi nghĩ rằng không nên từ chối trường hợp 3 và đặt '@ không được chấp thuận 'ở Javadoc có thể là phương sách cuối cùng, nếu không có cách tiếp cận nào tốt hơn. –

+0

Vì bạn đang tham khảo nó như là kiểu thay vì lớp, bạn có thể mở rộng bằng cách sử dụng kiểu generic, và cast vào 'DeprecatedClass' sau này, với một sự hạn chế cảnh báo xung quanh diễn viên? – CharlieS

Trả lời

7

Tôi rất tiếc khi nói rằng tôi không có giải pháp cho vấn đề bạn đang gặp phải, mặc dù bạn đã quan sát, đã có một số tiến bộ. Chúng tôi đã cố gắng loại bỏ tất cả các cảnh báo biên dịch Java trong bản thân JDK, và đây là một quá trình lâu dài và khó khăn. Trong quá trình phát triển JDK 8 năm 2011, tôi đã giúp kick off the warnings cleanup effort và sau đó tôi co-presented a JavaOne talk (slides and audio) về chủ đề này.

Gần đây hơn, số dặm của tôi Joe Darcy đã tiếp tục công việc dọn dẹp cảnh báo và đã làm việc thông qua các danh mục cảnh báo khác nhau và có finally reached deprecation warnings. Như bạn đã lưu ý, đã có một số lỗi trong việc xử lý của trình biên dịch ngăn chặn cảnh báo không dùng nữa, chẳng hạn như JDK-6480588 đã được sửa trong JDK 8. Thật không may, vẫn không thể có trong JDK 8 để ngăn chặn cảnh báo về việc nhập các mục không dùng nữa. Lỗi này, JDK-8032211, đã được sửa chữa khá gần đây trong dòng phát triển JDK 9 của chúng tôi. Thực tế, chúng tôi vẫn đang điều chỉnh việc xử lý chú thích @Deprecated. Ví dụ: lỗi JDK-6481080 làm rõ rằng cố gắng sử dụng @Deprecated trong tệp package-info.java không thực sự không dùng nữa gói; lỗi này đã được sửa vào tuần trước. Và có more work to be done nhưng nó có phần đầu cơ vào thời điểm này.

JDK đang đối mặt với các vấn đề tương tự như của bạn, trong đó chúng tôi phải duy trì API không dùng nữa cho các khách hàng vẫn đang sử dụng chúng. Nhưng kể từ khi chúng tôi sử dụng và triển khai các API như vậy trong nội bộ, chúng tôi có rất nhiều cảnh báo không dùng nữa để ngăn chặn. Theo văn bản này, trong dòng phát triển JDK 9 của chúng tôi, chúng tôi vẫn còn không thể biên dịch hệ thống mà không có cảnh báo không dùng nữa. Kết quả là, các javac tùy chọn cho việc cảnh báo lint vẫn là:

-Xlint:all,-deprecation 

Bạn có thể sẽ phải vô hiệu hóa cảnh báo deprecation trong biên dịch của bạn là tốt, đặc biệt là nếu bạn vẫn đang xây dựng trên JDK 6. Tôi không thấy một xung quanh nó vào thời điểm này.

Một lưu ý cuối cùng về một trong những trường hợp deprecation của bạn:

@Deprecated 
public class DeprecatedClass extends Bar<DeprecatedClass> { ... } 

này không đưa ra cảnh báo không dùng nữa, và cũng không nên nó.Java Language Specification, section 9.6.4.6, chỉ định rằng cảnh báo không dùng nữa sẽ không được ban hành nếu việc sử dụng thực thể không được chấp nhận nằm trong một thực thể không được chấp nhận.

+0

Cảm ơn bạn đã làm rõ và chia sẻ phát triển JDK. –

+0

Lưu ý cuối cùng là thú vị, bởi vì tôi thề rằng tôi đã phải thêm @SuppressWarnings ("không được chấp nhận") vào các phương thức đã được @Deprecated trước đây ... – Trejkaz

+0

@Trejkaz Vui lòng đăng một ví dụ nếu bạn tìm thấy. –

-3

Thông thường, khi bạn ngừng sử dụng lớp học, bạn không muốn bất kỳ ai sử dụng nó trong các phiên bản sau. Ngoài ra, codebase CỦA BẠN cũng nên ngừng sử dụng lớp không dùng nữa. Có vẻ lạ, khi bạn nói tất cả mọi người không sử dụng lớp MySuperDeprecatedUtil nhưng vẫn tiếp tục sử dụng nó trong codebase của bạn.

Nếu bạn cần sử dụng lớp MySuperDeprecatedUtil trong một số lớp khác - bạn nên đánh dấu lớp mà bạn sử dụng nó ở dạng @Deprecated - mọi lớp sử dụng mã không dùng nữa sẽ bị phản đối hoặc sẽ tạo cảnh báo biên dịch hoặc cần xóa hoặc nên ngừng sử dụng mã không dùng nữa.

Nếu bạn không thể ngừng sử dụng lớp học của mình - có thể còn quá sớm để không dùng nữa?

Trong thực tế của mình, khi tôi muốn ngừng sử dụng một số lớp, tôi tạo lớp thay thế, ví dụ: MySuperFreshUtil. Chuyển đổi tất cả các lớp bằng cách sử dụng MySuperDeprecatedUtil để MySuperFresh util giữ các giao diện nếu có thể (nếu không thể - sử dụng FQCN và phương thức đánh dấu là không được chấp nhận). Đánh dấu MySuperDeprecatedUtil là @Được chấp nhận và thêm nhận xét cho lớp học nào và cách sử dụng nên được sử dụng thay thế. Sau đó, tôi cam kết thay đổi này trong một danh sách thay đổi duy nhất.

+1

Giả sử bạn có 10 việc triển khai một định dạng tệp trừu tượng, để tương thích ngược. Mọi người chỉ nên sử dụng định dạng mới nhất, vì vậy bạn không dùng nữa 9. Nhà máy tạo đối tượng thích hợp cho một tệp nhất định vẫn phải tạo các phiên bản khác 9. Bạn không thể chỉ loại bỏ phương thức, vì nó sẽ phá vỡ ngược khả năng tương thích. Bạn cũng không thể từ chối phương thức factory vì nó vẫn được sử dụng khi đọc các tập tin. Vì vậy, theo logic này, giải pháp duy nhất là bỏ đánh dấu 9 lần triển khai cũ để chúng không còn bị phản đối nữa. Tôi không chắc chắn tôi muốn. – Trejkaz

1

Cân nhắc sử dụng -Xmaxwarns, bạn có thể kiểm soát số lượng cảnh báo trước khi dừng.

Hoặc thử thu thập số lượng cảnh báo và không thực hiện quá trình tích hợp, không biên soạn.

Ví dụ: https://issues.apache.org/jira/browse/HADOOP-11252. Mọi mã cam kết với dự án hadoop cần phải vượt qua CI tự động và nó cho -1 để tăng số lượng cảnh báo.

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