Vaadin+Spring (without SpringBoot) with JavaConfig - java

i'm trying to combine vaadin with spring (without spring-boot) and java-annotation based configuration for the spring part.
The autowiring seems to work on the vaadin-ui part but not in "custom-ui classes" (e.g. "public class LoginScreen extends CustomComponent"). I'm getting an NPE or a null-object on SysOut.
Further i noticed that "#ComponentScan(basePackages={"net.myapp"})" is not scanning for beans. The only way to declare beans is in the CustomConfiguration itself.
XML-Configuration is not something i prefer.
I'm following this Tutorial: Link
CustomConfiguration.java
#Configuration
#ComponentScan(basePackages={"net.myapp"})
#EnableVaadin
public class CustomConfiguration {
// this is working but i want to use componentscan!
#Bean
public String test() {
return "test...";
}
#Bean
public TestBean testBean() {
return new TestBean();
}
#Bean
public LoginScreen loginScreenBean() {
return new LoginScreen();
}
}
SpringVaadinServlet.java
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = Application.class)
#SuppressWarnings("serial")
public class SpringVaadinServlet extends VaadinServlet implements SessionInitListener {
#Autowired
protected VaadinUIProvider applicationProvider;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
AutowireCapableBeanFactory ctx = ((ApplicationContext)
getServletContext().getAttribute("applicationContext")).getAutowireCapableBeanFactory();
ctx.autowireBean(this);
}
#Override
protected void servletInitialized() {
getService().addSessionInitListener(this);
}
#Override
public void sessionInit(SessionInitEvent event) throws ServiceException {
event.getSession().addUIProvider(applicationProvider);
}
}
VaadinUIProvider.java
#SpringComponent
#SuppressWarnings("serial")
public class VaadinUIProvider extends UIProvider {
#Autowired
ApplicationContext applicationContext;
#Override
public Class<? extends UI> getUIClass(UIClassSelectionEvent event) {
return Application.class;
}
#Override
public UI createInstance(UICreateEvent event) {
UI instance = new Application();
System.out.println("applicationContext is null? " + applicationContext);
applicationContext.getAutowireCapableBeanFactory().autowireBean(instance);
return instance;
}
}
SpringApplicationContextListener.java
#WebListener
public class SpringApplicationContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(CustomConfiguration.class);
sce.getServletContext().setAttribute("applicationContext", applicationContext);
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
Application.java
#Theme("mytheme1")
#SpringUI
#SuppressWarnings("serial")
public class Application extends UI {
#Autowired
private TestBean testBean;
#Autowired
private String test;
#Override
protected void init(VaadinRequest vaadinRequest) {
// working
System.out.println("init testBean: " + testBean);
System.out.println("init test: " + test);
Window window = new Window();
window.setContent(new LoginScreen());
window.setClosable(false);
window.setWidth("400px");
window.setHeight("280px");
window.setModal(true);
window.setDraggable(false);
window.setResizable(false);
window.center();
addWindow(window);
setSizeFull();
}
}
And the following "custom-ui class"
LoginScreen.java
#UIScope
#SuppressWarnings("serial")
public class LoginScreen extends CustomComponent {
public static final String VIEW_NAME = "";
final FormLayout layout = new FormLayout();
TextField userName = new TextField();
TextField passWord = new TextField();
Button submit = new Button("Submit");
#Autowired
private TestBean testBean;
#Autowired
private String test;
public LoginScreen() {
userName.setCaption("Benutzername:");
passWord.setCaption("Passwort:");
// not working (null)
System.out.println("loginscreen test: " + testBean);
System.out.println("loginscreen test: " + test);
setSizeFull();
}
}
I'd appreciate some help...

window.setContent(new LoginScreen());
Spring should create LoginScreen if you want that #Autowired annotated fields become injected.
Just inject the LoginScreen instance in your Application class

Related

Spring MVC Pass Bean Object to RestController from embedded Tomcat

I am building a REST API into an existing Spring Java application and I am not sure how to pass the Bean to the Rest Controller from the Main part of the app.
I would like to be able to have the Bean IDao created with its database instance passed into the UserController so it can be used as shown below.
As is, it is not able to autowire the Bean into the UserController. If I change the ComponentScan to include the main package it will autowire but not without ending up in and infinite Bean creation loop. What am I doing wrong?
package com.app.main;
public class App {
private static AnnotationConfigApplicationContext ctx;
public static void main(String[] args) throws Exception {
ctx = new AnnotationConfigApplicationContext(RestApiConfig.class);
}
}
package com.app.main;
#Configuration
public class RestApiConfig {
#Bean
public IDao<User> userDao(Database database) {
return new DatabaseDao<>(database, User.class);
}
#Bean
public Database database() {
return new Database();
}
#Bean
public RestApi restApi(IDao<User> userDao) {
return new RestApi(userDao);
}
package com.app.rest;
public class RestApi {
private final int PORT = 8080;
private final IDao<User> userDao;
public RestApi( IDao<User> userDao) {
this.userDao = userDao;
run();
}
public void run() {
String contextPath = "/api";
String webappDir = new File("src/main/webapp").getAbsolutePath();
Tomcat tomcat = new Tomcat(); // Tomcat 9.x.x
tomcat.setPort(PORT);
tomcat.getConnector(); // Trigger the creation of the default connector
Context context = tomcat.addWebapp(contextPath, webappDir);
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
tomcat.getServer().await();
}
}
package com.app.rest;
#Configuration
#EnableWebMvc
#ComponentScan({"com.app.rest"})
public class RestApiServletConfig {
}
package com.app.rest;
public class RestApiServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ RestApiServletConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[]{ "/" };
}
}
package com.app.rest;
#RestController
public class UserController {
private final IDao<User> repository;
UserController(IDao<User> repository) {
this.repository = repository;
}
#GetMapping("/users/{id}")
public User userById(#PathVariable Long id) {
return repository.get(id);
}
}

Spring Boot does not inject #Autowired repository into netty classes

I have a Spring Boot application with the following structure:
com.test (Root Class)
com.test.jpa (JPA Entities and Repositories)
com.test.netty (netty TCP server)
The root class is:
#ComponentScan(basePackages = {"com.test"})
//#EnableJpaRepositories
//#EntityScan
public class MyApplication {
...
The Netty Server:
package com.test.netty;
#Service
#Slf4j
public class NettyServer {
private EventLoopGroup boss = new NioEventLoopGroup();
private EventLoopGroup work = new NioEventLoopGroup();
#PostConstruct
public void start() {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, work).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
// .option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingHandler(LogLevel.INFO)).childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true).childHandler(new ServerChannelInit());
try {
ChannelFuture future = bootstrap.bind().sync();
if (future.isSuccess()) {
log.info("Netty Server Started!");
}
} catch (InterruptedException ie) {
log.error("Error Initializing Netty Server. Error: " + ie.getMessage());
}
}
#PreDestroy
public void destroy() throws InterruptedException {
boss.shutdownGracefully().sync();
work.shutdownGracefully().sync();
log.info("Netty Server Shut Down!");
}
and:
public class ServerChannelInit extends ChannelInitializer<SocketChannel>{
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("mainHandler", new ServiceHandler());
}
and:
package com.test.netty;
#Component
public class ServiceHandler extends ChannelInboundHandlerAdapter {
private SomeEntity en;
#Autowired
SomeRepository sr;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Read data and persist some entitys using injected repository
And repository:
package com.test.jpa;
//#Repository
public interface SomeRepository extends JpaRepository<SomeEntity, BigInteger> {
}
The problem is: Repository is not injected into com.test.netty classes. I use it in root class and in JUnit tests without any problem.
I added #Repository to the repository and also added repo packages in #EnableJPARepositories but nothing changed.
Any ideas?
Well, if you're creating an instance of ServiceHandler yourself rather than using the bean instance Spring creates for you, of course no dependency injection will be performed. You need to inject the ServiceHandler bean into ServerChannelInit as well as make ServerChannelInit a #Component itself:
#Component
public class ServerChannelInit extends ChannelInitializer<SocketChannel>{
private final ServiceHandler handler;
public ServerChannelInit(ServiceHandler handler) {
this.handler = handler;
}
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("mainHandler", handler);
}
...
}
and then inject ServerChannelInit into NettyServer:
#Service
#Slf4j
public class NettyServer {
private final ServerChannelInit channelInit;
public NettyServer(ServerChannelInit channelInit) {
this.channelInit = channelInit;
}
private EventLoopGroup boss = new NioEventLoopGroup();
private EventLoopGroup work = new NioEventLoopGroup();
#PostConstruct
public void start() {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, work).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
// .option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingHandler(LogLevel.INFO)).childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true).childHandler(channelInit);
...
}
I just executed with the followings, just add #SpringBootApplication in your main class. Uncomment #Repository
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
#Repository
public interface SomeRepository extends JpaRepository<Person, BigInteger> {
void foo();
}
#Component
public class SampleRepo implements SomeRepository{
#Override
public void foo() {
System.out.println("Called...." );
}
}
#RestController
public class ServiceHandler {
#Autowired
private SomeRepository sr;
#GetMapping("/hello")
public void call(){
sr.foo();
}
}
It works!

Dependency Injection with interface in Spring

I've a MainHandler class :
#Component
class MainHandler {
//inject this
private Handler handler;
#Autowired
public MainHandler(Handler handler){
this.handler = handler;
}
public void action(String message){
//watch photo
if (message.equals("photo")){
handler.handle();
}
if(message.equals("audio")){
//play music
handler.handle();
}
if(message.equals("video")){
//play video
handler.handle();
}
}
And following other handlers with interface.
Can I inject dependencies with Spring Boot by only interface type handler?
#Component
public interface Handler {
void handle();
}
#Component
class PhotoHandler implements Handler {
public void handle(){
System.out.println("Featuring photo...");
}
}
#Component
class VideoHandler implements Handler {
public void handle(){
System.out.println("Playing video...");
}
}
#Component
class AudioHandler implements Handler {
public void handle(){
System.out.println("Playing music...");
}
}
Or I want to try something like this below. Is it possible ?
class MainHandler {
private VideoHandler videoHandler;
private AudioHandler audioHandler;
private PhotoHandler photoHandler;
#Autowired
public MainHandler(VideoHandler videoHandler,
AudioHandler audioHandler,
PhotoHandler photoHandler) {
this.videoHandler = videoHandler;
this.audioHandler = audioHandler;
this.photoHandler = photoHandler;
}
public void action(String message){
//watch photo
if (message.equals("photo")){
photoHandler.handle();
}
if(message.equals("audio")){
//play music
audioHandler.handle();
}
if(message.equals("video")){
//play video
videoHandler.handle();
}
}
}
So, type of handler depends on user's message. I don't know how Spring can choose which handler gonna be used in this context. Any solution?
There can be multiple solution to this case.
Option #1
You can tweak a design of your handler a bit.
For instance you can introduce a method
boolean canHandle(String message);
so each handler can answer whether passed message can be handled or not.
Then you can inject a list of all handlers into your MainHandler.
private List<Handler> handlers;
Now having that list you can call each handler by message:
public void action(String message) {
handlers.stream()
.filter(h -> h.canHandle(message))
.forEach(handler -> handler.handle());
}
Full example:
#SpringBootApplication
public class SO62370917 {
public static void main(String[] args) {
SpringApplication.run(SO62370917.class, args);
}
#Component
static class MainHandler {
private final List<Handler> handlers;
MainHandler(List<Handler> handlers) {
this.handlers = handlers;
}
public void action(String message) {
handlers.stream()
.filter(h -> h.canHandle(message))
.forEach(Handler::handle);
}
}
#Bean
CommandLineRunner cmd(MainHandler mainHandler) {
return args -> {
mainHandler.action("video");
mainHandler.action("audio");
mainHandler.action("photo");
};
}
interface Handler {
void handle();
boolean canHandle(String message);
}
#Component
class PhotoHandler implements Handler {
public void handle(){
System.out.println("Featuring photo...");
}
#Override
public boolean canHandle(String message) {
return "photo".equals(message);
}
}
#Component
class VideoHandler implements Handler {
public void handle(){
System.out.println("Playing video...");
}
#Override
public boolean canHandle(String message) {
return "video".equals(message);
}
}
#Component
class AudioHandler implements Handler {
public void handle(){
System.out.println("Playing music...");
}
#Override
public boolean canHandle(String message) {
return "audio".equals(message);
}
}
}
Option #2
Use qualifiers.
You can name your handlers however you like and then inject a Map<String, Handler> into your mainHandler. The key would be a bean name and the value - the actual handler. Spring will automatically take care of this.
#SpringBootApplication
public class SO62370917 {
public static void main(String[] args) {
SpringApplication.run(SO62370917.class, args);
}
#Component
static class MainHandler {
private final Map<String, Handler> handlers;
MainHandler(Map<String, Handler> handlers) {
this.handlers = handlers;
}
public void action(String message) {
if (handlers.containsKey(message)) {
handlers.get(message).handle();
}
}
}
#Bean
CommandLineRunner cmd(MainHandler mainHandler) {
return args -> {
mainHandler.action("video");
mainHandler.action("audio");
mainHandler.action("photo");
};
}
interface Handler {
void handle();
}
#Component("photo")
class PhotoHandler implements Handler {
public void handle() {
System.out.println("Featuring photo...");
}
}
#Component("video")
class VideoHandler implements Handler {
public void handle() {
System.out.println("Playing video...");
}
}
#Component("audio")
class AudioHandler implements Handler {
public void handle() {
System.out.println("Playing music...");
}
}
}
The output:
2020-06-14 13:06:47.140 INFO 29447 --- [ main] com.example.demo.SO62370917 : Started SO62370917 in 1.356 seconds (JVM running for 1.795)
Playing video...
Playing music...
Featuring photo...
There are two simple ways in which you can approach :
Recommended : You can use #Qualifier to inject the desired particular bean.
For example
#Component
class MainHandler {
#Autowired
#Qualifier("videoHandler") // example
private Handler handler;
public void action(){
handler.message(); // this will print playing video...
}
}
You can inject the ApplicationContext.
For example :
#Component
class MainHandler {
#Autowired
private ApplicationContext context;
public void action(String message){
//watch photo
if (message.equals("photo")){
((PhotoHandler) context.getBean(PhotoHandler.class)).handle();
}
if(message.equals("audio")){
//play music
((AudioHandler) context.getBean(AudioHandler.class)).handle();
}
if(message.equals("video")){
//play video
((VideoHandler) context.getBean(VideoHandler.class)).handle();
}
}
}

In Spring Boot which class would be initialize first #Component or #Configuration

I have a class annotated with #Component which is use to initialze application.yml config properties. Service classe is using configuration property. But sometime my Service class instance created before the Configuration class and I get null property value in service class, Its random not specific pattern.
Configuration Initializer class..
#Component
public class ConfigInitializer implements InitializingBean {
private static final Logger log = LoggerFactory.getLogger(ConfigInitializer.class);
#Autowired
ProxyConfig proxyConfig;
/*#PostConstruct
public void postConstruct(){
setProperties();
}
*/
#Override
public void afterPropertiesSet() {
setProperties();
}
private void setSystemProperties(){
log.debug("Setting properties...");
Properties props = new Properties();
props.put("PROXY_URL", proxyConfig.getProxyUrl());
props.put("PROXY_PORT", proxyConfig.getProxyPort());
System.getProperties().putAll(props);
}
}
#Component
#ConfigurationProperties(prefix = "proxy-config")
public static class ProxyConfig {
private String proxyUrl;
private String proxyPort;
public String getProxyUrl() {
return proxyUrl;
}
public void setProxyUrl(String proxyUrl) {
this.proxyUrl = proxyUrl;
}
public String getProxyPort() {
return proxyPort;
}
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
}
Service Class..
#Service("receiverService")
public class ReceiverService {
private static final Logger logger = LoggerFactory.getLogger(ReceiverService.class);
private ExecutorService executorService = Executors.newSingleThreadExecutor();
#Autowired
public ReceiverService() {
initClient();
}
private void initClient() {
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
String value = System.getProperty("PROXY_URL"); **//Here I am getting null**
logger.info("Values : " + value);
}
});
System.out.println("future.get() = " + future.get());
}
}
Above Service class get null values String value = System.getProperty("PROXY_URL")
When I use #DependsOn annotation on Service class, it works fine.
In my little knowledge, I know Spring does not have specific order of bean creation.
I want to know If I use #Configuration instead of #Component on ConfigInitializer class like below, Will spring initialize ConfigInitializer
class before other beans ?.
#Configuration
public class ConfigInitializer implements InitializingBean {
//code here
}

Spring Websocket MessageSendingOperation not working without #Scheduled

.
.
.
#Autowired
private MessageSendingOperations<String> messagingTemplate;
#Scheduled(fixedDelay = 5000)
public void sendMessage(){
messagingTemplate.convertAndSend("/topic/data","hello");
}
}
The above works. but
sendMessage();
public void sendMessage(){
messagingTemplate.convertAndSend("/topic/data", "hello");
}
}
doesn't work, it got java.lang.NullPointerException
Does that mean I could only use messagingTemplate.convertAndSend(...) inside a function annotated with #Scheduled?
Please help...
#Deendayal Garg, thanks for your help, I did this this according to your advice:
public class Communicator implements ApplicationListener {
private final MessageSendingOperations<String> messagingTemplate;
#Autowired
public Communicator(final MessageSendingOperations<String> messagingTemplate){
this.messagingTemplate = messagingTemplate;
}
public void onApplicationEvent(BrokerAvailabilityEvent event) {
// TODO Auto-generated method stub
}
public void sendMessage(Message data) {
this.messagingTemplate.convertAndSend("/topic/data",data.getBody());
System.out.println(new Random().nextInt(100));
}
}
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(
final DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public Communicator communicator(){
Communicator comm = new Communicator();
return comm;
}
}
Then I injected the bean in the class below
public class StepExecListener implements StepExecutionListener, ApplicationListener<BrokerAvailabilityEvent>{
#Autowired
Communicator communicator;
Message msg = new Message();
msg.setBody("Twale!");
msg.setType("test");
communicator.sendDataUpdates(msg);
}
But I still got it got java.lang.NullPointerException after calling communicator.sendDataUpdates(msg);

Categories