Aplicação Swing com Spring Boot

Vou precisar criar um projeto pequeno em Java e precisa ser Desktop.
Gostaria de usar as facilidades do Spring Boot que já uso para Web, porém não consigo usar o CDI dele.

Ao criar um JFrame ou JInternalFrame, dentro dele não consigo usar o @Autowired em um @Service ou @Repository. Ocorre NullPointerException.

As interfaces de Repository não podem instanciadas manualmente.

@Component // não funciona com ou sem essa anotação
public class MinhaTela extends JFrame {

    @Autowired
    private MyRepository myRepository;

}

@Repository
public interface MyRepository extends CrudRepository<MeuTipo, Long> {}
1 curtida

vc conseguiu resolver o seu problema estou com o msm problema que o seu,vi que ninguem respondeu aqui.
Se vc conseguiu me da uma força…

vc pode usar o SpringBoot como servidor a parte e integrar com o Swing. Eu gosto de usar o OkHttp no Java pra ligar com requisições.

mais como que faço pra chamar o repository no jframe?
usando o @component?

Vc tem algum conteudo pra mim indicar?

São aplicações separadas… o spring boot é o servidor que vc vai acessar via endpoint. O swing é seu “front end”.

Pelos meus testes, o ideal é o seu JFrame não ser um bean.

Vc vai declarar as dependências dele no construtor e vai instanciá-lo manualmente. Por exemplo:

class Window extends JFrame {
  public Window(PokemonService pokemonService) {
    super.setLayout(new BoxLayout(super.getContentPane(), BoxLayout.Y_AXIS));
    pokemonService.getAll().forEach(pokemon -> super.add(new JLabel(pokemon.getName())));
    super.setSize(300, 300);
    super.setLocationRelativeTo(null);
    super.setDefaultCloseOperation(EXIT_ON_CLOSE);
    super.setVisible(true);
  }
}

E a sua classe principal estaria assim:

@SpringBootApplication
class Application {
  public static void main(String... args) {
    new SpringApplicationBuilder(Application.class).headless(false).run(args);
  }

  @Bean
  CommandLineRunner runner1(PokemonRepository pokemonRepository) {
    return args -> pokemonRepository.saveAll(
      List.of(
        new Pokemon(1, "Bulbasaur"),
        new Pokemon(4, "Chamander"),
        new Pokemon(7, "Squirtle"),
        new Pokemon(25, "Pikachu")
      )
    );
  }

  @Bean
  CommandLineRunner runner2(PokemonService pokemonService) {
    return args -> SwingUtilities.invokeLater(() -> new Window(pokemonService));
  }
}

Note que usei SpringApplicationBuilder com headless(false) para tudo funcionar corretamente.

Este aqui é o código completo que usei para testar

Meu build.gradle:

plugins {
  id 'java'
  id 'org.springframework.boot' version '3.1.0'
  id 'io.spring.dependency-management' version '1.1.0'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  runtimeOnly 'com.h2database:h2'
}

Meu application.properties está vazio.

Meu código Java:

package com.example;

import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
class Pokemon {
  @Id
  private long number;

  private String name;

  protected Pokemon() {
  }

  public Pokemon(long number, String name) {
    this.number = number;
    this.name = name;
  }

  public long getNumber() {
    return this.number;
  }

  public String getName() {
    return this.name;
  }
}

interface PokemonRepository extends JpaRepository<Pokemon, Long> {
}

@Service
class PokemonService {
  @Autowired
  private PokemonRepository pokemonRepository;

  public List<Pokemon> getAll() {
    return this.pokemonRepository.findAll();
  }
}

class Window extends JFrame {
  public Window(PokemonService pokemonService) {
    super.setLayout(new BoxLayout(super.getContentPane(), BoxLayout.Y_AXIS));

    pokemonService.getAll().forEach(pokemon -> super.add(new JLabel(pokemon.getName())));

    super.setSize(300, 300);
    super.setLocationRelativeTo(null);
    super.setDefaultCloseOperation(EXIT_ON_CLOSE);
    super.setVisible(true);
  }
}

@SpringBootApplication
class Application {
  public static void main(String... args) {
    new SpringApplicationBuilder(Application.class).headless(false).run(args);
  }

  @Bean
  CommandLineRunner runner1(PokemonRepository pokemonRepository) {
    return args -> pokemonRepository.saveAll(
      List.of(
        new Pokemon(1, "Bulbasaur"),
        new Pokemon(4, "Chamander"),
        new Pokemon(7, "Squirtle"),
        new Pokemon(25, "Pikachu")
      )
    );
  }

  @Bean
  CommandLineRunner runner2(PokemonService pokemonService) {
    return args -> SwingUtilities.invokeLater(() -> new Window(pokemonService));
  }
}

Pô, as aplicações tem que ficar juntas?

Então, eu não sei se eu entendi direito.

O que eu entendi é que eles querem tirar proveito da injeção de dependencia do Spring em uma aplicação Swing.

Já o jeito que vc sugeriu, onde vc falou sobre servidor, vc interpretou que eles tem uma aplicação Swing que será cliente de uma outra aplicação feita com Spring. Mas eu acho que não é isso que eles querem, acho que há apenas um aplicação desktop e eles querem usar injeção de dependencias nela.

1 curtida

Que doideira…

Você quer colocar tudo na mesma aplicação né !?

Quer que sua aplicação se comporta como Cliente e Servidor?

Se for isso, nada te impede de fazer duas aplicações rodando no desktop e eles conversarem entre si e oferecer saidas e entradas de dados.

Pela descrição, ele não quer o modelo cliente-servidor.

Ele tem um JFrame e quer que este JFrame seja gerenciado pelo container de injeção de dependencia.

Se no JFrame ele exibe uma lista, como no meu exemplo, ele não quer enviar uma requisição HTTP, mesmo que local, para pegar esta lista, ele quer pegar esta lista direto do repository. No meu exemplo eu ainda coloquei uma camada de service.

Entendi