2016-02-09 16 views
10

Używam Spring AOP, a zatem pośrednio CGLIB w moim kontroler Spring MVC. Od CGLIB potrzebuje domyślnego konstruktora włączyłem jeden i mój kontroler teraz wygląda tak:Jak zapobiec ostrzeżeniom o błędnych błędach przy korzystaniu z CGLIB/Spring AOP?

@Controller 
public class ExampleController { 

    private final ExampleService exampleService; 

    public ExampleController(){ 
     this.exampleService = null; 
    } 

    @Autowired 
    public ExampleController(ExampleService exampleService){ 
     this.exampleService = exampleService; 
    } 

    @Transactional 
    @ResponseBody 
    @RequestMapping(value = "/example/foo") 
    public ExampleResponse profilePicture(){ 
     return this.exampleService.foo(); // IntelliJ reports potential NPE here 
    } 
} 

Problem jest teraz, że analiza statyczna kodu IntelliJ IDEA donosi potencjalny NullPointerException, ponieważ this.exampleService może być null.

Moje pytanie brzmi:

Jak uniknąć tych fałszywych pozytywnych ostrzeżenia NULL? Jednym rozwiązaniem byłoby dodanie assert this.exampleService != null lub może użyć Guawa Preconditions.checkNotNull(this.exampleService).

Należy to jednak dodać do każdej metody dla każdego pola użytego w tej metodzie. Wolałbym rozwiązanie, które mógłbym dodać w jednym miejscu. Może adnotacja na domyślnym konstruktorze czy coś takiego?

EDIT:

wydaje się być mocowane za pomocą sprężyny 4, jednak obecnie używam Spring 3: http://blog.codeleak.pl/2014/07/spring-4-cglib-based-proxy-classes-with-no-default-ctor.html

+1

Czy ten konstruktor rzeczywiście musi być wywoływalny, czy po prostu musi istnieć? Czy możesz rzucić wyjątek? – chrylis

+0

Jedną z opcji jest użycie AspectJ weaver w czasie kompilacji lub środowiska wykonawczego, a nie cglib. Spring docs wyjaśniają, jak to zrobić. Jedną z korzyści tego podejścia jest to, że pozwala on na iniekcję zależności i oprzyrządowanie obiektów domen, które zwykle są "anemiczne". Innym jest wspieranie klas, które będą wyposażone w interfejs, i dlatego używają dynamicznego proxy zamiast cglib - w zależności od charakteru klasy może to być dobra praktyka. –

+0

Czy problem nadal występuje, gdy występuje 'setter' dla' exampleService'? – 11thdimension

Odpowiedz

3

można opisywać swoje pole (jeśli jesteś pewien, że to naprawdę nie będzie be null) z:

//import org.jetbrains.annotations.NotNull; 
@NotNull 
private final ExampleService exampleService; 

Spowoduje to, że Pomysł przyjmie, że to pole będzie miało wartość-null we wszystkich przypadkach. W tym przypadku twój prawdziwy konstruktor zostanie również odnotowany automatycznie idea:

public ExampleController(@NotNull ExampleService exampleService){ 
    this.exampleService = exampleService; 
} 
+0

Myślę, że to jest tak dobre, jak to tylko możliwe. Miałem nadzieję na coś takiego jak adnotacja '@ IgnoreNotUsed' dodawana do argumentującego contruktora, ale to wcale nie jest takie złe ... –

0
statyczna analiza kodu

IntelliJ IDEA donosi potencjalny NullPointerException

można wyłączyć te raporty dla poszczególnych pól, zmiennych, metody, itp. przy użyciu @SuppressWarnings ({"odznaczone", "Nieużywane deklaracje"}) lub komentarz. W rzeczywistości IDEA może sama zaproponować to rozwiązanie. Zobacz https://www.jetbrains.com/idea/help/suppressing-inspections.html

Można przełączać ostrzeganie za pomocą pojedynczego wiersza kodu:

void foo(java.util.Set set) { 
    @SuppressWarnings("unchecked") 
    java.util.Set<String> strings = set; 
    System.out.println(strings); 
} 
+0

Potencjalne NullPointerExceptions-ostrzeżenia są całkiem użyteczne i nie chcę ich dezaktywować ani całkowicie stłumić. –

+0

Możesz wyłączyć dla określonego wiersza kodu, a nie dla całej klasy wyjątków –

+0

Jak napisałem w moim pytaniu, mógłbym użyć 'assert this.exampleService! = Null', które jest znacznie bardziej wyraziste niż' @ SuppressWarnings'. Jednak nie chcę dodawać twierdzeń w każdym miejscu. –

0

Można by utworzyć domyślną nową instancję ExampleService i przypisać go do domyślnego konstruktora zamiast przypisać go do wartości null:

public ExampleController(){ 
    this.exampleService = new ExampleService(); 
} 

lub

public ExampleController(){ 
    this.exampleService = ExampleServiceFactory.Create(); 
} 

Od th obiekt nie powinien nigdy być używany w normalnym działaniu, nie będzie miał żadnego efektu, ale jeśli obiekt zostanie użyty przez framework lub przypadkowo użyty bezpośrednio z powodu późniejszych zmian kodu, da to więcej informacji w ślad stosu niż wyjątek wskaźnika pustego, a to rozwiąże również błąd, że this.exampleService może mieć wartość NULL.

Może to wymagać pewnych zmian w klasie ExampleService, aby umożliwić utworzenie nowej instancji z domyślnymi parametrami lub umożliwić utworzenie nowej instancji, która jest w zasadzie powłoką, która nic nie robi.Jeśli dziedziczy po typie interfejsu podstawowego, klasa niefunkcjonalna może dziedziczyć z tego samego typu bazowego, co konkretnie jako obiekt zastępczy. Ten wzorzec pozwala także wprowadzić kod obsługi błędów, aby zapewnić wyraźne ostrzeżenie, jeśli aplikacja spróbuje użyć domyślnej niefunkcjonalnej instancji.

Odkryłem, że w językach takich jak Java i C#, gdzie prawie wszystko jest wskaźnikiem, poleganie na wskaźnikach zerowych nawet w obszarach, w których nigdy nie powinny być używane, sprawia, że ​​konserwacja jest trudniejsza niż powinna, ponieważ często mogą być używane przypadkowo . Podstawowe maszyny wirtualne są zaprojektowane tak, aby odpowiadały atakowi paniki, gdy kod próbuje użyć wskaźnika zerowego - podejrzewam, że jest to spowodowane dziedzictwem C, w którym wskaźniki zerowe mogą naprawdę zepsuć cały działający program. Z powodu tego wirtualnego ataku paniki, nie dostarczają żadnych użytecznych informacji, które pomogłyby zdiagnozować problem, zwłaszcza, że ​​wartość (null) jest całkowicie bezużyteczna dla identyfikacji tego, co się stało. Dzięki unikaniu wskaźników zerowych, a zamiast tego projektowaniu hierarchii klas w celu ustalenia, czy instancjonowany obiekt powinien wykonać jakąkolwiek prawdziwą pracę, można uniknąć potencjalnych problemów z wskaźnikami zerowymi, a także uczynić swój kod łatwiejszym i bezpieczniejszym w utrzymaniu.

Powiązane problemy