Search code examples
javaspringsystem-trayheadless

Spring Boot use SystemTray Icons


I am setting up a Spring Boot Application and would like to have the host have access to a System Tray Icon with access to some bean Information.

I currently Tried to Create a Bean for my SystemTrayIcon with the @Autowired details. However When I try to add the SystemTrayIcon I get the following Exception:

Caused by: java.awt.HeadlessException
    at java.awt.TrayIcon.<init>(Unknown Source)
    at java.awt.TrayIcon.<init>(Unknown Source)
    at java.awt.TrayIcon.<init>(Unknown Source)
    at hermes.subsrciber.systemTray.HermesTrayIcon.<init>(HermesTrayIcon.java:36)
    at hermes.subscriber.boot.AppStarter.trayIcon(AppStarter.java:83)
    at hermes.subscriber.boot.AppStarter$$EnhancerBySpringCGLIB$$c4f80849.CGLIB$trayIcon$3(<generated>)
    at hermes.subscriber.boot.AppStarter$$EnhancerBySpringCGLIB$$c4f80849$$FastClassBySpringCGLIB$$d62ab0bd.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
    at hermes.subscriber.boot.AppStarter$$EnhancerBySpringCGLIB$$c4f80849.trayIcon(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
    ... 17 more

Is there any way that a SpringBoot Application can have access to System Tray Icons?

I believe I CAN simply define it in the Main method (alongisde the SpringApplication.run) however I would not be able to autowire my properties.

Is this setup possible?


Solution

  • The Solution is, rather than using SpringApplication.run(MyConfig.class,args), use the following setup:

        SpringApplicationBuilder builder = new SpringApplicationBuilder(MyConfig.class);
        builder.headless(false);
        ConfigurableApplicationContext context = builder.run(args);
    

    To actually add the System Icon I then added a bean of the followign type:

    public class MyTrayIcon extends TrayIcon {
    
        private static final String IMAGE_PATH = "/path/icon_16x16.png";
        private static final String TOOLTIP = "Text";
    
        private PopupMenu popup;
        private SystemTray tray;
    
        public MyTrayIcon(){
            super(createImage(IMAGE_PATH,TOOLTIP),TOOLTIP);
            popup = new PopupMenu();
            tray = SystemTray.getSystemTray();
        }
    
        @PostConstruct
        private void setup() throws AWTException{
            // popup.add(itemAbout);
            // here add the items to your popup menu. These extend MenuItem
            // popup.addSeparator();
            setPopupMenu(popup);
            tray.add(this);
        }
    
        protected static Image createImage(String path, String description){
            URL imageURL = MyTrayIcon.class.getResource(path);
            if(imageURL == null){
                System.err.println("Failed Creating Image. Resource not found: "+path);
                return null;
            }else {
                return new ImageIcon(imageURL,description).getImage();
            }
        }
    }