@Path("/abc")
@Produces(MediaType.APPLICATION_JSON)
public class ABCController
{
@Autowired
private MyService myService;
@GET
public Response getSome(@QueryParam("identification") List<String> ids)
{
GenericEntity<List<Label>> entity = new GenericEntity<>(myService.findSomething(ids))
{
};
return Response.ok(entity).build();
}
МойСервис:
@RequiredArgsConstructor
@Service
public class MyService
{
private final MyMapper myMapper;
private final JpaRepository myRepository;
public List<String> findSomething(ids){
myRepository.findXYZ(ids);
}
Мой основной класс:
@SpringBootApplication
public class MainClass
{
public static void main(String[] args)
{
SpringApplication.run(MainClass.class, args);
}
@Bean
public MyMapper myMapper()
{
return new MyMapperImpl();
}
}
построить.градле:
buildscript {
ext {
LOMBOK_VERSION = "1.18.22"
SPRING_BOOT_VERSION = "2.6.6"
JERSEY_VERSION = "3.0.8"
JACKSON_VERSION = "2.13.1"
MSSQL_JDBC_VERSION = "9.4.1.jre11"
MAPSTRUCT = "1.5.1.Final"
}
}
plugins {
id "org.gretty" version "4.0.3"
}
apply plugin: 'java-library'
apply plugin: 'java'
apply plugin: 'war'
repositories {
mavenLocal()
maven {
url = '...'
}
}
dependencies {
compileOnly "org.projectlombok:lombok:${LOMBOK_VERSION}"
testImplementation "org.projectlombok:lombok:${LOMBOK_VERSION}"
annotationProcessor "org.projectlombok:lombok:${LOMBOK_VERSION}"
implementation "org.mapstruct:mapstruct:${MAPSTRUCT}"
annotationProcessor "org.mapstruct:mapstruct-processor:${MAPSTRUCT}"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:${SPRING_BOOT_VERSION}"
implementation "com.microsoft.sqlserver:mssql-jdbc:${MSSQL_JDBC_VERSION}"
implementation "org.glassfish.jersey.containers:jersey-container-servlet-core:${JERSEY_VERSION}"
implementation "org.glassfish.jersey.inject:jersey-hk2:${JERSEY_VERSION}"
implementation "org.glassfish.jersey.media:jersey-media-json-jackson:${JERSEY_VERSION}"
}
Когда я звоню http://localhost:8080/myservice/abc?identification=61234561234569,71234561234568,71234561234569
я получил NullPointerException
из myService.findSomething(ids)
Я запускаю приложение с помощью команды gradle appRun
Отвечает ли это на ваш вопрос? Что такое исключение NullPointerException и как его исправить?
Проблема: для «автоматической проводки» запрашивающий объект должен быть «пружинным управлением» ... ваш ABCController, похоже, не такой!
Так что аннотация @Component
на ABCController исправит это...
... у вас есть альтернативные варианты (@Bean
в классе конфигурации (развязка...!), или @Service
, @Repository
аннотации, ... и я пытаюсь выяснить, что было бы лучшим/общим для "Jakarta ws". .
Для авто-проводки: оба объекта (проводные и проводные) должны быть "пружинными (бинами)"! ;) В MyService это достигается с помощью аннотации @Service
.
@Stultuske не имеет значения, и я это знаю. Вопрос в том, почему я должен его создавать. это сервисный объект
@emoleumassi вы читали комментарии xerx593? Это он уже объяснил. или вы говорили о полях в MyService? В этом случае да, MyService — это сервис, его поля — нет.
@Stultuske JpaRepository
- это JpaRepository
, и у меня есть боб MyMapper
в MainClass
Несмотря на то, что Spring предлагает свою собственную «инфраструктуру для разработки REST-Service» (spring-web ), не должно быть никаких причин, по которым JAX-RS не мог бы использовать spring-core и даже spring-boot.
Проблема (для этого конкретного NPE):
Для авто-проводки: оба объекта (проводные и проводные) должны быть "пружинными (бинами)"! ;) В MyService это достигается с помощью аннотации @Service.
Чтобы решить эту проблему, нам также нужно подключить ABCController в контексте spring!
«Наименее навязчивый»/самый простой подход — аннотировать ABCController
с помощью @Component
:
...
import org.springframework.stereotype.Component;
@Component // !
@Path("/abc")
@Produces(MediaType.APPLICATION_JSON)
public class ABCController ...
Это (+ правильное «сканирование компонентов») «поднимет» ABCController в контекст весны и включит автоматическое подключение (от/к) этого объекта.
Другой подход, отделяющий «реализации» от spring:
Для этого нам нужно удалить все (возможные) org.springframework.*
импорты из наших «пружинно-независимых» классов. (Конечно, это невозможно в очень специфичных классах spring (spring-web(Rest)Controllers, Spring-data-repos,...).
@Component/Service/Repository
, мы перемещаем экземпляры в аннотированные методы @Bean
в нашу конфигурацию Spring (класс (ы)) (.. см. Бин MyMapper!)@Autowired
, нам пришлось бы «связывать» их вручную или использовать «автоматическое связывание неявного конструктора» (в рамках упомянутых методов @Bean
)Итак, ваш Config(/SpringBootApp) может выглядеть так:
@SpringBootApplication
public class MainClass
{
public static void main(String[] args)
{
SpringApplication.run(MainClass.class, args);
}
@Bean
public MyMapper myMapper()
{
return new MyMapperImpl();
}
@Bean // singleton is default "scope"!!...
public MyService myService(/*implicitly @Autowired :*/ JPARepository repo, MyMapper mapper /* ..and taken care (hopefully;) by spring*/) {
return new MyService(mapper, repo);
}
// and:
@Bean
public ABCController abcController(/*implicitly @Autowired :*/ MyService service /* ..and taken care (hopefully;) by spring*/) {
ABCController bean = new ABCController();
bean.setMyService(service);
return bean;
}
}
С соответствующими настройками ABCController:
@Path("/abc")
@Produces(MediaType.APPLICATION_JSON)
public class ABCController
{
// NOT @Autowired
private MyService myService;
...
// Setter(/getter) for myService !
При добавлении @RequiredArgsConstructor
к ABCController
подходящего конструктора найти не удалось. Ошибка: java.lang.NoSuchMethodException: Could not find a suitable constructor in ABCController class.
Вы пробовали "наименее навязчиво"? ..конечно @RequiredArgsConstructor
более навязчиво!!:)) ..но много альтернатив ..(один из них: удалить @RequiredArgsConstructor, удалить модификатор final
, ввести сеттер, ..использовать его в методе компонента..)
Итак, кажется, что jax-rs (.. или что-то в конце этой трассировки стека) нуждается в «конструкторе по умолчанию (т.е. без аргументов)» для ABCController..
Я обновил ответ, чтобы не использовать @RequiredArgsConstructor
..
Это зависимость для джерси в весенней загрузке: spring-boot-starter-jersey
build.gradle выглядит так:
buildscript {
ext {
LOMBOK_VERSION = "1.18.22"
SPRING_BOOT_VERSION = "2.6.6"
JERSEY_VERSION = "3.0.8"
JACKSON_VERSION = "2.13.1"
MSSQL_JDBC_VERSION = "9.4.1.jre11"
MAPSTRUCT = "1.5.1.Final"
}
}
apply plugin: 'java-library'
apply plugin: 'java'
apply plugin: 'war'
repositories {
mavenLocal()
maven {
...
}
}
dependencies {
compileOnly "org.projectlombok:lombok:${LOMBOK_VERSION}"
testImplementation "org.projectlombok:lombok:${LOMBOK_VERSION}"
annotationProcessor "org.projectlombok:lombok:${LOMBOK_VERSION}"
implementation "org.mapstruct:mapstruct:${MAPSTRUCT}"
annotationProcessor "org.mapstruct:mapstruct-processor:${MAPSTRUCT}"
implementation "org.springframework.boot:spring-boot-starter-jersey:${SPRING_BOOT_VERSION}"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:${SPRING_BOOT_VERSION}"
implementation "com.microsoft.sqlserver:mssql-jdbc:${MSSQL_JDBC_VERSION}"
}
Контроллер становится @Component
@Path("/abc")
@Produces(MediaType.APPLICATION_JSON)
@Component
public class ABCController
{
@Autowired
private MyService myService;
@GET
public Response getSome(@QueryParam("identification") List<String> ids)
{
GenericEntity<List<Label>> entity = new GenericEntity<>(myService.findSomething(ids))
{
};
return Response.ok(entity).build();
}
MainClass - это сервлет:
@SpringBootApplication
public class MainClass extends SpringBootServletInitializer
{
public static void main(String[] args)
{
new MainClass().configure(new SpringApplicationBuilder(MainClass.class)).run(args);
}
@Bean
public MyMapper myMapper()
{
return new MyMapperImpl();
}
}
MyService — это @Service
@RequiredArgsConstructor
@Service
public class MyService
{
Я добавил JerseyConfig:
@Component
public class JerseyConfig extends ResourceConfig
{
public JerseyConfig()
{
register(ABCController.class);
}
}
вы фактически не создаете экземпляры полей MyService. Итак: myRepository.findXYZ(ids); на самом деле: null.findXYZ(ids);