Home > Enterprise >  To call Strava API from SpringBoot application
To call Strava API from SpringBoot application

Time:11-07

I'm trying to develop my first java Spring Bboot app that calls Strava API and gets my activities for the given period of time. I've registered my app on Strava's website and got client_id and client secret. I've generated spring-swagger-codegen-api-client and awtowired the client to the app.

@Configuration
public class StravaIntegrationConfiguration {

    @Bean
    public ActivitiesApi stravaApi(){
        return new ActivitiesApi(apiClient());
    }

    @Bean
    public ApiClient apiClient(){
        return new ApiClient();
    }
}

Then I use this bean in AdapterClass

public class Adapter {
    @Autowired
    private static ActivitiesApi activitiesApi;
    
    public static void getActivities(Integer before, Integer after, Integer page, Integer perPage) {
        final List<SummaryActivity> loggedInAthleteActivities = activitiesApi.getLoggedInAthleteActivities(before, after, page, perPage);
        System.out.println("ВСЕГО АКТИВНОСТЕЙ"  loggedInAthleteActivities.size());
    }
}
@SpringBootApplication
@Import(StravaIntegrationConfiguration.class)
public class App {

    public static void main(String[] args) throws SQLException {
        SpringApplication.run(App.class);
        Adapter.getActivities(1636130496, 1635529296, 1,  30);

    }
}

When I run this code I get NPE, because activitiesApi is null.
What is the problem? Please kindly advise. Does it concern authentication? Could you advise also any code sample on how to make Strava authentication in my app?

CodePudding user response:

You can't use autowire with static fields. More info can be found in this link: Can you use @Autowired with static fields?

CodePudding user response:

It has nothing to do with Strava authentication. It is related to Spring context and Spring Beans and how to inject them. As already mentioned you can't autowire Spring-managed beans in static fields (it makes no sense actually). Having said that you need to fix that first:

@Component
public class Adapter {
    @Autowired
    private ActivitiesApi activitiesApi;
    
    public void getActivities(Integer before, Integer after, Integer page, Integer perPage) {
        final List<SummaryActivity> loggedInAthleteActivities = activitiesApi.getLoggedInAthleteActivities(before, after, page, perPage);
        System.out.println("ВСЕГО АКТИВНОСТЕЙ"  loggedInAthleteActivities.size());
    }
}

Also, note that the method changed from a static one to an instance one and that the annotation @Component was added to the class. The reason is that a Spring-managed bean can only be injected into other Spring-managed beans.

Additionally, it seems to me that you are trying to do something after the Spring context has been initialized. One possible way to do this is creating a bean that implements the ApplicationListener interface:

@Component
public class StartupApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private Adapter adapter;

    @Override 
    public void onApplicationEvent(ContextRefreshedEvent event) {
        adapter.getActivities(1636130496, 1635529296, 1,  30);
    }
}

This means that you can and you should remove the line Adapter.getActivities(1636130496, 1635529296, 1, 30); from your main class:

@SpringBootApplication
@Import(StravaIntegrationConfiguration.class)
public class App {

    public static void main(String[] args) throws SQLException {
        SpringApplication.run(App.class);
    }
}

Finally, and as a side note, please consider using constructor injection instead of field injection. It has a couple of advantages over field injection: making the class easier to unit test, allowing the objects to be immutable, explicitly definition of which dependencies are mandatory, etc... (you can read more at https://reflectoring.io/constructor-injection/).

  •  Tags:  
  • java
  • Related