Исключение Null Pointer в Spring Proxy Class и Kotlin

Я столкнулся с некоторыми проблемами с котлином в связи с весной.

У меня есть компонент контроллера (без интерфейса btw), который имеет компонент с автоматической проводной связью через первичный конструктор.

Он отлично работает, если я не использую аннотации кэширования для контроллера. По-видимому, кэширование springs генерирует прокси-класс под капотом, который имеет дело с кешированием.

Мой код выглядит так:

@RestController @RequestMapping("/regions/") open class RegionController @Autowired constructor(val service: RegionService) { @RequestMapping("{id}", method = arrayOf(RequestMethod.GET)) @Cacheable(cacheNames = arrayOf("regions")) fun get(@PathVariable id: Long): RegionResource { return this.service.get(id) } } 

Проблема теперь представляет собой исключение с нулевым указателем при выполнении метода, на самом деле this.service является null что технически невозможно, так как оно является ненулевой переменной в kotlin.

Я предполагаю, что прокси-классы, сгенерированные весной, инициализируют класс с нулевыми значениями, а не с автосогласованным компонентом. Это должно быть обычным явлением с использованием котлина и весны. Как вы обошли эту проблему?

По умолчанию в Котлине оба класса и члены являются окончательными .

Для прокси-библиотеки ( CGLIB , javaassist ), чтобы иметь возможность прокси-метода, он должен быть объявлен не окончательным и в не финальном классе ( поскольку эти библиотеки реализуют проксирование путем подкласса ). Измените свой метод контроллера на:

 @RequestMapping("{id}", method = arrayOf(RequestMethod.GET)) @Cacheable(cacheNames = arrayOf("regions")) open fun get(@PathVariable id: Long): RegionResource { return this.service.get(id) } 

Вероятно, вы видите предупреждение в консоли относительно методов RegionController которые не подлежат проксированию.

Плагин компилятора Kotlin

Команда Kotlin признала эту @Component и создала плагин, который отмечает стандартные кандидаты на прокси- @Component AOP, например, @Component с open .

Вы можете включить плагин в build.gradle :

 plugins { id "org.jetbrains.kotlin.plugin.spring" version "1.1.60" } 

Вскоре это уже не проблема.

Происходит работа над тем, что любая lib (включая весну, например) может указать список аннотаций файла в META-INF. Как только класс аннотируется одним из них, он по умолчанию будет открыт для самого класса и всех его функций. Это также верно для классов, наследуемых от аннотированного класса.

Для получения дополнительной информации см. https://github.com/Kotlin/KEEP/pull/40#issuecomment-250773204