2016-09-19 5 views
0

Мой вопрос касается инициализации нестатического поля с использованием статических методов. В основном мой кодИнициализация нестатического поля

@NoArgsConstructor 
@Builder 
public class MyClass implements Callable<MyResultClass>{{ 

     @Setter private MyService service; 

     List<MyType> myList = 
     Collections.synchronizedList(new ArrayList<MyType>()); 

    //.... other fields methods and so on 
    } 

Я нахожу во время моего теста Спока, что myList является недействительным после этого заявления (в каждом вызове метода). Я решил инициализировать его в конструкторе, но я не могу понять, почему он равен нулю. Может ли кто-нибудь объяснить мне это поведение и, если возможно, дать мне некоторую ссылку, чтобы лучше понять инициализацию поля статическими методами? Спасибо

Я согласен со всеми вами, я не понимаю, что здесь не так. Я использую lombok builder для создания этого экземпляра Callable. Я бегу тест Спока, как это в intellij2016

class InboundMessageListenerSpec extends Specification{ 
     private MyService service = Mock(MyService) 

     given: 
     def myClassObject = MyClass.builder().service(service).build() 
     ....other objects 

     when: 
     //stimulus that also starts the thread 

     then: 
     1 * service.myMethod() 
    } 

Проблема здесь в том, что при отладке этого теста я заметил, что он бросает NullPointerException когда (в методе стимула) он использует Синхронное список, который является недействительным.

Я попытался заменить строителя нормальным созданием экземпляра и инъекцией поля, и все работает как аспект. Мне нужно исследовать поведение строителя ломбок.

Трассировка стека:

java.lang.NullPointerException: null 
    at org.fw.adapters.secondary.NetworkInventoryDataAdapter.deleteCvlanRows(NetworkInventoryDataAdapter.java:111) 
    at org.fw.kernel.flows.executors.StartMigrationExecutor.call(StartMigrationExecutor.java:114) 
    at org.fw.kernel.flows.executors.StartMigrationExecutor.call(StartMigrationExecutor.java:34) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 
    at java.lang.Thread.run(Thread.java:662) 

линия 111 представляет собой цикл по каждому элементу в приведенном выше списке

+2

Невозможно. Доказательства, пожалуйста. Процесс инициализации определен в [Спецификация Java Language # 12.5] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5). – EJP

+0

Я тестировал, 'mylist' приводит к пустым списком, когда я новый' MyClass' – passion

+1

Можете ли вы опубликовать немного больше своего кода, чтобы мы могли видеть, как вы подтверждаете, что оно равно нулю? – Aelexe

ответ

0

Это хорошо известная проблема. Вы используете @Builder, что позволяет вам устанавливать все поля. И он это делает. Попробуйте delombok, чтобы узнать, что происходит.

Я не уверен, о деталях, но она идет вдоль этой линии: - ваш @Builder использует @AllArgsContructor - вы не установили myList в строитель, поэтому он остается null - null переходит в руки ваши @AllArgsContructor - копирует его во вновь созданный объект (*)

Это issue 916. Не совсем ошибка, просто удивительное поведение. Вам лучше использовать @Builder только для неизменяемых, где нет проблем и где вам это действительно нужно.


(*) В Java код конструктора выполняется после выражения инициализатора.

+0

Привет, спасибо за ваше объяснение. Я использовал delombok, и поведение точно так же, как вы описали. Большое спасибо за детали и ссылки. – Raffaele

Смежные вопросы