I'm implementing a simple REST api using SpringBoot and maven and one part consists in reading the response from a webserver and save it in the mySql DB. I'm trying to use the JpaRepository of the object Response to save the response into de DB but for some reason the repository is null. I found another post where the problem seemed tp be in the controller but i can't figure out why and where my error is
I tried injecting the repository direcply in the forst service instead of calling the save() funvtion in loadDBService but it is't working either
My error: Cannot invoke "com.baeldung.api.repositories.ResponseRepository.save(Object)" because "this.responseRepository" is null
my pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>provaYaml</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<gson-fire-version>1.9.0</gson-fire-version>
<okhttp-version>4.11.0</okhttp-version>
<gson-version>2.10.1</gson-version>
<commons-lang3-version>3.14.0</commons-lang3-version>
<jackson-databind-nullable-version>0.2.6</jackson-databind-nullable-version>
<jakarta-annotation-version>1.3.5</jakarta-annotation-version>
<junit-version>5.10.0</junit-version>
<junit-platform-runner.version>1.10.0</junit-platform-runner.version>
<javax.ws.rs-api-version>2.1.1</javax.ws.rs-api-version>
<jsr311-api-version>1.1.1</jsr311-api-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spotless.version>2.43.0</spotless.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.4.6</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp-version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>${okhttp-version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson-version}</version>
</dependency>
<dependency>
<groupId>io.gsonfire</groupId>
<artifactId>gson-fire</artifactId>
<version>${gson-fire-version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3-version}</version>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>${jakarta-annotation-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>${jsr311-api-version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>${javax.ws.rs-api-version}</version>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>${junit-platform-runner.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0-M2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.5.0.Final</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.1.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>
${project.basedir}/src/main/resources/v0.1.yaml
</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>com.baeldung.openapi.api</apiPackage>
<modelPackage>com.baeldung.openapi.model</modelPackage>
<supportingFilesToGenerate>
ApiUtil.java
</supportingFilesToGenerate>
<configOptions>
<delegatePattern>true</delegatePattern>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
My controller:
package com.baeldung.api.controller;
import com.baeldung.api.service.ForecastApiDelegate;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Generated;
import java.util.Optional;
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2024-05-02T13:05:10.503984100+02:00[Europe/Rome]")
@Controller
@RequestMapping("${openapi.meteo.base-path:}")
public class ForecastApiController implements ForecastApi {
private final ForecastApiDelegate delegate;
public ForecastApiController(@Autowired(required = false) ForecastApiDelegate delegate) {
this.delegate = Optional.ofNullable(delegate).orElse(new ForecastApiDelegate() {});
}
@Override
public ForecastApiDelegate getDelegate() {
return delegate;
}
}
My forecastGetService
package com.baeldung.api.service;
import com.baeldung.api.model.Response;
import com.baeldung.api.repositories.ResponseRepository;
import com.baeldung.openapi.api.ForecastApiDelegate;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
@Service
public class ForecastGetService implements ForecastApiDelegate {
private Logger log = LogManager.getLogger(ForecastGetService.class);
@Override
public ResponseEntity<String> forecastGet(Float latitude, Float longitude, String hourly) {
try {
return new ResponseEntity<>(getData(latitude, longitude, hourly), HttpStatus.OK);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String getData(Float latitude, Float longitude, String hourly) throws Exception {
log.trace("getData");
LoadDBService loadDBService = new LoadDBService();
URL url = new URL("https://api.open-meteo.com/v1/forecast?latitude="+ latitude +"&longitude=" + longitude+ "&hourly=" + hourly);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
loadDBService.createResponse(con);
if(con.getResponseCode() < 200 || con.getResponseCode() >= 300){
throw new RuntimeException("Risposta dal server non corretta");
}
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
return content.toString();
}
}
my loadDBService
package com.baeldung.api.service;
import com.baeldung.api.dtos.RequestDto;
import com.baeldung.api.dtos.ResponseDto;
import com.baeldung.api.model.Request;
import com.baeldung.api.model.Response;
import com.baeldung.api.repositories.RequestRepository;
import com.baeldung.api.repositories.ResponseRepository;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
@Service
public class LoadDBService{
@Autowired
private RequestRepository requestRepository;
@Autowired
private ResponseRepository responseRepository;
private Logger log = LogManager.getLogger(ForecastGetService.class);
public LoadDBService(){
}
public ResponseDto extractResponse(HttpURLConnection con) throws IOException, URISyntaxException {
String status = String.valueOf(con.getResponseCode());
String responseMessage = con.getResponseMessage();
URI uri = con.getURL().toURI();
ResponseDto responseDto = new ResponseDto();
responseDto.setUri(uri.toString());
responseDto.setResposeMessage(responseMessage);
responseDto.setStatusCode(status);
return responseDto;
}
public void createRequest(RequestDto tmp){
Request request = new Request(tmp);
requestRepository.save(request);
}
public void createResponse(HttpURLConnection con) throws IOException, URISyntaxException {
log.trace("metodo createResponse");
ResponseDto tmp = extractResponse(con);
Response response = new Response(tmp);
responseRepository.save(response);
}
}
my repository:
package com.baeldung.api.repositories;
import com.baeldung.api.model.Response;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ResponseRepository extends JpaRepository<Response, Integer> { }
my Response object
package com.baeldung.api.model;
import com.baeldung.api.dtos.ResponseDto;
import jakarta.persistence.*;
import org.springframework.data.annotation.Id;
import java.io.Serializable;
@Entity
@Table (name = "web_server_response")
public class Response implements Serializable {
@Id
@GeneratedValue (strategy = GenerationType.AUTO)
private int response_id;
private String resposeMessage;
private String statusCode;
private String uri;
public Response() {}
public Response(int response_id, String resposeMessage, String statusCode, String uri) {
this.response_id = response_id;
this.resposeMessage = resposeMessage;
this.statusCode = statusCode;
this.uri = uri;
}
public Response(ResponseDto responseDto){
this.uri = responseDto.getUri();
this.resposeMessage = responseDto.getResposeMessage();
this.statusCode = responseDto.getStatusCode();
}
public int getResponse_id() {
return response_id;
}
public void setResponse_id(int response_id) {
this.response_id = response_id;
}
public String getResposeMessage() {
return resposeMessage;
}
public void setResposeMessage(String resposeMessage) {
this.resposeMessage = resposeMessage;
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}
my hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection properties - Driver, URL, user, password -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/requests</property>
<property name="hibernate.connection.username">test</property>
<property name="hibernate.connection.password">test123</property>
<!-- Outputs the SQL queries, should be disabled in Production -->
<property name="hibernate.show_sql">true</property>
<!-- Dialect is required to let Hibernate know the Database Type, MySQL, Oracle
Hibernate 4 automatically figure out Dialect from Database Connection Metadata -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- mapping file, we can use Bean annotations too -->
<mapping class="com.baeldung.api.model.Response" />
<mapping class="com.baeldung.api.model.Request" />
</session-factory>
</hibernate-configuration>
You are doing a LoadDBService loadDBService = new LoadDBService();
in the ForecastGetService
class instead of injecting it using Spring with @Autowired
. If you create LoadDBService
with new
, the @Autowired
fields of it are not injected by Spring.
Remove the new LoadDBService()
line and add this other line in the ForecastGetService
:
@Autowired
private LoadDBService loadDBService;