2011-12-28 41 views
22

Tôi có rất nhiều mã boilerplate rằng về cơ bản sau mô hình này:Java chú thích cho gói một phương pháp

function doSomething() { 
    try { 
    [implementation] 
    [implementation] 
    [implementation] 
    [implementation] 
    } catch (Exception e) { 
    MyEnv.getLogger().log(e); 
    } finally { 
    genericCleanUpMethod(); 
    } 
} 

Tôi rất muốn tạo chú thích của riêng tôi để làm sạch mã của tôi lên một chút:

@TryCatchWithLoggingAndCleanUp 
function doSomething() { 
    [implementation] 
    [implementation] 
    [implementation] 
    [implementation] 
} 

Chữ ký phương thức khác nhau một cách dữ dội (tùy thuộc vào việc thực hiện phương pháp thực tế), nhưng phần thử/catch/bản cuối cùng của lò hơi luôn giống nhau.

Chú thích tôi lưu ý sẽ tự động bao bọc nội dung của phương thức được chú thích với toàn bộ số try...catch...finally hoopla.

Tôi đã tìm kiếm cao và thấp một cách đơn giản để thực hiện việc này nhưng không tìm thấy gì. Tôi không biết, có lẽ tôi không thể nhìn thấy khu rừng cho tất cả các cây được chú thích.

Bất kỳ con trỏ nào về cách tôi có thể triển khai chú thích như vậy sẽ được đánh giá cao.

+0

Dường như với tôi chú thích sẽ không cần thiết cho việc này; bạn có thể chỉ cần truyền các hiện thực xác định 'implementationOfDoSomething()' và (tùy chọn, có lẽ) 'genericCleanUpMethod()' làm đối số cho 'doSomething()', gọi chúng trong 'try/catch/finally', và sau đó chỉ cần gọi' doSomething() 'bất cứ khi nào bạn cần logic boilerplate? –

+1

Câu trả lời của bạn nằm trong AOP, bạn đã nghiên cứu về điều này chưa? – smp7d

+0

Sự hiểu biết của tôi là anh ta có cùng một thử/bắt/cuối cùng trên nhiều phương pháp. Vì vậy, không chỉ có một doSomething đơn lẻ, nhưng giống như doSomething1, doSomething2, ... tất cả cùng với try/catch/cuối cùng mà anh ta muốn giải nén vào chú thích – jeff

Trả lời

19

Để thực hiện việc này, bạn sẽ cần một số khung công tác AOP sẽ sử dụng proxy xung quanh phương pháp của bạn. Proxy này sẽ bắt ngoại lệ và thực thi khối cuối cùng. Hoàn toàn thẳng thắn, nếu bạn không sử dụng một khung công tác hỗ trợ AOP, tôi không chắc chắn tôi sẽ sử dụng một cái chỉ để lưu vài dòng mã od này.

Bạn có thể sử dụng mô hình sau đây để làm điều này trong một cách thanh lịch hơn, mặc dù:

public void doSomething() { 
    logAndCleanup(new Callable<Void>() { 
     public Void call() throws Exception { 
      implementationOfDoSomething(); 
      return null; 
     } 
    }); 
} 

private void logAndCleanup(Callable<Void> callable) { 
    try { 
     callable.call(); 
    } 
    catch (Exception e) { 
     MyEnv.getLogger().log(e); 
    } 
    finally { 
     genericCleanUpMethod(); 
    } 
} 

tôi chỉ sử dụng Callable<Void> như một giao diện, nhưng bạn có thể định nghĩa giao diện Command riêng bạn:

public interface Command { 
    public void execute() throws Exception; 
} 

và do đó tránh sự cần thiết phải sử dụng chung Callable<Void> và trả về null từ Gọi.

CHỈNH SỬA: trong trường hợp bạn muốn trả lại nội dung nào đó từ phương pháp của mình, sau đó thực hiện phương thức logAndCleanup() chung chung. Dưới đây là một ví dụ hoàn chỉnh:

public class ExceptionHandling { 
    public String doSomething(final boolean throwException) { 
     return logAndCleanup(new Callable<String>() { 
      public String call() throws Exception { 
       if (throwException) { 
        throw new Exception("you asked for it"); 
       } 
       return "hello"; 
      } 
     }); 
    } 

    public Integer doSomethingElse() { 
     return logAndCleanup(new Callable<Integer>() { 
      public Integer call() throws Exception { 
       return 42; 
      } 
     }); 
    } 

    private <T> T logAndCleanup(Callable<T> callable) { 
     try { 
      return callable.call(); 
     } 
     catch (Exception e) { 
      System.out.println("An exception has been thrown: " + e); 
      throw new RuntimeException(e); // or return null, or whatever you want 
     } 
     finally { 
      System.out.println("doing some cleanup..."); 
     } 
    } 

    public static void main(String[] args) { 
     ExceptionHandling eh = new ExceptionHandling(); 

     System.out.println(eh.doSomething(false)); 
     System.out.println(eh.doSomethingElse()); 
     System.out.println(eh.doSomething(true)); 
    } 
} 

EDIT: Và với Java 8, mã bọc có thể là một chút đẹp hơn:

public String doSomething(final boolean throwException) { 
    return logAndCleanup(() -> {     
     if (throwException) { 
      throw new Exception("you asked for it"); 
     } 
     return "hello";     
    }); 
} 
+0

+1 - Đây là những gì tôi đã nhận được trong các ý kiến ​​của tôi về câu hỏi. –

+0

Điều này rất giống với giải pháp "Kế hoạch B" của riêng tôi, nên chú thích cuối cùng là không thực tế. Mà có vẻ là trường hợp. Cảm ơn rất nhiều! – TroutKing

+0

Cảm ơn vì điều này, các công trình tuyệt vời nếu bạn không trả lại bất cứ điều gì, nhưng nếu 'callable' cần phải trả lại một cái gì đó. Bạn có phải tạo một 'ExecutorService' như được nêu ở đây không ?: http://stackoverflow.com/a/5516955/293280 –

0

afaik bạn sẽ phải theo dõi từng cuộc gọi phương thức cho chú thích @TryCatchWithLoggingAndCleanUp, điều này sẽ rất tẻ nhạt. về cơ bản bạn có thể nhận được từng phương thức chú thích bằng cách phản ánh và sau đó thực hiện xử lý ngoại lệ và ghi nhật ký của bạn. nhưng tôi không chắc bạn có muốn làm điều đó không.

3

bạn có thể tự thực hiện chú thích và chú thích chú thích và mã công cụ mỗi khi bạn biên dịch (javac -processor). Cách khác là sử dụng AOP, nói AspectJ hoặc Spring AOP (Nếu bạn sử dụng Spring).

11

Bạn có thể sử dụng proxy động để thực hiện điều này. Phải mất một chút thiết lập, nhưng một khi thực hiện, là khá đơn giản.

Trước tiên, bạn xác định giao diện và đặt chú thích trên giao diện.

public interface MyInterface { 
    @TryCatchWithLogging 
    public void doSomething(); 
} 

Bây giờ, khi bạn muốn cung cấp triển khai giao diện cho người tiêu dùng, thay vào đó, hãy cung cấp cho người dùng.

MyInterface impl = new java.lang.reflect.Proxy.newProxyInstance(
         Impl.class.getClassLoader(), 
         Impl.class.getInterfaces(), YourProxy(new Impl()); 

Sau đó, triển khai YourProxy.

public class YourProxy implements InvocationHandler { 
.... 

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     if (method.isAnnotationPresent(TryCatchLogging.class)) { 
       // Enclose with try catch 
} 
Các vấn đề liên quan