0

I have written a very small Spring Boot application in Java8 which should consume a REST web service.

Here are the main classes:

application.properties

api.url=https://rest-api.com

DataServiceConfiguration.java

package com.client.service.rest;

@Configuration
public class DataHubServiceConfiguration {

    public static final String URL_DELIMITER = "/";

    @Value("${api.url}")
    private String apiUrl;

    @Bean
    public DataClientService dataClientService() {
        DataClientService clientService = new DataClientService();
        clientService.setApiUrl(apiUrl);
        clientService.setRestTemplate(new RestTemplate());

        return clientService;
    }
}

ClientService.java

package com.client.service.rest;

@Service
public class ClientService {

    private String apiUrl;

    @Autowired
    private final RestTemplate restTemplate;

    public ResponseDTO getData(RequestDTO request) {
        String url = constructFullEndpoint(Endpoint.GET_DATA);
        ResponseDTO data = restTemplate.getForObject(url, ResponseDTO.class, request);

        return data;
    }

    public void setApiUrl(String apiUrl) {
        this.apiUrl = apiUrl;
    }

    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    private String constructFullEndpoint(ApiEndpoint endpoint) {
        return apiUrl + URL_DELIMITER + endpoint.getName();
    }
}

DataApplication.java

package com.client.service.rest;

@SpringBootApplication
public class DataApplication extends Application {
    private static String[] args;

    @Autowired
    private ClientService client;

    public static void main(String[] args) {
        DataApplication.args = args;
        Application.launch(DataApplication.class, args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Label lblMethod = new Label("Method");
        ChoiceBox<String> method = new ChoiceBox<>(FXCollections.observableArrayList(
            Arrays.stream(Endpoint.values()).map(Endpoint :: getName).collect(Collectors.toList())));

        Label lblInputJson = new Label("Request (JSON)");
        TextArea inputJson = new TextArea();

        Label lblOutputJson = new Label("Response (JSON)");
        TextArea outputJson = new TextArea();

        Button btn = new Button("Send");
        btn.setOnAction(event -> {
            Endpoint endpoint =   Endpoint.getByName(method.getSelectionModel().getSelectedItem());
            String inputJsonStr = inputJson.getText();
            String outputJsonStr = "";
            Gson gson = new GsonBuilder().setPrettyPrinting().create();

            outputJsonStr = gson.toJson(client.getData(gson.fromJson(inputJsonStr, RequestDTO.class)));
                
            outputJson.setText(outputJsonStr);
        });

        VBox layout= new VBox(5);

        layout.getChildren().addAll(lblMethod, method, lblInputJson, inputJson, lblOutputJson, outputJson, btn);

        StackPane root = new StackPane(layout);
        root.setPadding(new Insets(5, 10, 10, 10));

        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.setTitle("DataHub Client Service");
        primaryStage.getIcons().add(new Image(DataApplication.class.getResourceAsStream("/logo.png")));
        primaryStage.setOnCloseRequest(e -> {
            Platform.exit();
            System.exit(0);
        });

        primaryStage.show();

        new Thread(() -> {
            new SpringApplicationBuilder(DataApplication.class).run(args);
        }, "Spring Thread").start();
    }
}

build.gradle fragment

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework:spring-beans')
    compile('org.springframework:spring-context')
    compileOnly('org.projectlombok:lombok:1.18.26')
    implementation('com.google.code.gson:gson:2.10.1')
}

application.properties file and logo.png image are located in resources folder.

Here are the problems I'm facing with:

  1. When the application is run on MacOS the image isn't shown on the Dock. Even though I tried this solution as well:

    URL iconURL = getClass().getResource("puzl_ogo.png"); java.awt.Image icon = new ImageIcon(iconURL).getImage(); com.apple.eawt.Application.getApplication().setDockIconImage(icon);

and run the application with -XDignore.symbol.file

  1. The @Autowired ClientService client; is null even though during the application start I see that the @Bean method is being called and the objects are being instantiated.

  2. When I manually instantiate the client it's restTemplate and apiUrl are null which is normal since manually created object is out of scope of Spring managed beans.

So my questions are:

  1. How to fix the icon issue for the Dock?
  2. What's the problem with autowired fields and how to fix them?
Armine
  • 1,675
  • 2
  • 24
  • 40
  • Spring is only able to inject into instances that it created. Your main class was not created by Spring, therefore Spring cannot inject into it. – DwB Jun 09 '23 at 13:33
  • @DwB, but my main class wasn't created by Spring when it is annotated as `@SpringBootApplication`? Also, if it's not, then how the `@Bean` methods are being called when launching the application? – Armine Jun 09 '23 at 13:39
  • Does this answer your question? [Spring-Boot @Autowired in main class is getting null](https://stackoverflow.com/questions/31399924/spring-boot-autowired-in-main-class-is-getting-null) – Abhishek Jun 09 '23 at 16:47
  • I believe the issue is related to how you try to bootstrap your Spring Boot app within JFX Application. It isn't working. Check my answer here [How to bootstrap JavaFX application within Spring Boot application?](https://stackoverflow.com/questions/73462910/how-to-run-spring-boot-javafx-maven-project-with-java-17/75259080#75259080) – eHayik Jun 10 '23 at 07:25

1 Answers1

0

Eventually, I couldn't find a solution for images but for SpringBootApplication issue found a solution here and did the following:

package com.client.service.rest;

@SpringBootApplication
public class DataApplication extends Application {
    private static String[] args;

    @Autowired
    private ClientService client;

    private ConfigurableApplicationContext context;

    public static void main(String[] args) {
        DataApplication.args = args;
        Application.launch(DataApplication.class, args);
    }

    @Override
    public void init() {
        context = SpringApplication.run(getClass(), args);
        context.getAutowireCapableBeanFactory().autowireBean(this);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Label lblMethod = new Label("Method");
        ChoiceBox<String> method = new ChoiceBox<>(FXCollections.observableArrayList(
            Arrays.stream(Endpoint.values()).map(Endpoint :: getName).collect(Collectors.toList())));

        Label lblInputJson = new Label("Request (JSON)");
        TextArea inputJson = new TextArea();

        Label lblOutputJson = new Label("Response (JSON)");
        TextArea outputJson = new TextArea();

        Button btn = new Button("Send");
        btn.setOnAction(event -> {
            Endpoint endpoint =   Endpoint.getByName(method.getSelectionModel().getSelectedItem());
            String inputJsonStr = inputJson.getText();
            String outputJsonStr = "";
            Gson gson = new GsonBuilder().setPrettyPrinting().create();

            outputJsonStr = gson.toJson(client.getData(gson.fromJson(inputJsonStr, RequestDTO.class)));
            
            outputJson.setText(outputJsonStr);
        });

        VBox layout= new VBox(5);

        layout.getChildren().addAll(lblMethod, method, lblInputJson, inputJson, lblOutputJson, outputJson, btn);

        StackPane root = new StackPane(layout);
        root.setPadding(new Insets(5, 10, 10, 10));

        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.setTitle("DataHub Client Service");
    
        primaryStage.show();
    }

    @Override
    public void stop() throws Exception {
        super.stop();
        context.close();
        System.exit(0);
    }
}
Armine
  • 1,675
  • 2
  • 24
  • 40