Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Headless mode is forced when banner.* file is present. #28803

Closed
jfarjona opened this issue Nov 24, 2021 · 3 comments
Closed

Headless mode is forced when banner.* file is present. #28803

jfarjona opened this issue Nov 24, 2021 · 3 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@jfarjona
Copy link

jfarjona commented Nov 24, 2021

Create any SpringBoot project and add a banner.png on the resources folder.
Set this as the main application class:

@SpringBootApplication
public class RunSimulators implements ApplicationRunner {
    private static final Logger                   log = LoggerFactory.getLogger(RunSimulators.class);
    
    /**
     * Method description
     *
     * @param osArgs
     */
    public static void main(String[] osArgs) {
        SpringApplication app = new SpringApplicationBuilder(RunSimulators.class).web(WebApplicationType.NONE)
                                                                                 .headless(false)
                                                                                 .build();

        app.setWebApplicationType(WebApplicationType.NONE);
        app.setHeadless(false);        
        ctx = app.run(osArgs);
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {       
        System.out.println("Headless run: " + String.valueOf(GraphicsEnvironment.isHeadless()));
    }
}

You would expect " Headless run: false ", but you get true. Remove the banner.png file, and now it is false.

Somehow having a banner forces the application to run headless, no matter what we do.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 24, 2021
@wilkinsona
Copy link
Member

The headless property is set and its previous value reinstated as part of printing the image-based banner:

@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
String headless = System.getProperty("java.awt.headless");
try {
System.setProperty("java.awt.headless", "true");
printBanner(environment, out);
}
catch (Throwable ex) {
logger.warn(LogMessage.format("Image banner not printable: %s (%s: '%s')", this.image, ex.getClass(),
ex.getMessage()));
logger.debug("Image banner printing failure", ex);
}
finally {
if (headless == null) {
System.clearProperty("java.awt.headless");
}
else {
System.setProperty("java.awt.headless", headless);
}
}
}

Given that SpringApplication already sets the system property, I'm not sure that this is necessary although changing it could break code using ImageBanner outside of SpringApplication.

@wilkinsona wilkinsona added the for: team-attention An issue we'd like other members of the team to review label Nov 24, 2021
@philwebb
Copy link
Member

I think the problem we have is that we can't actually reset java.awt.headless once a call to GraphicsEnvironment.isHeadless has been called. The GraphicsEnvironment caches the value in a private static Boolean.

When using the ImageBanner, the ImageReader triggers Rectangle.<clinit>() which calls GraphicsEnvironment.isHeadless and sets things in stone.

Thread [main] (Suspended (breakpoint at line 167 in GraphicsEnvironment))	
	GraphicsEnvironment.getHeadlessProperty() line: 167	
	GraphicsEnvironment.isHeadless() line: 145	
	Rectangle.<clinit>() line: 174	
	ImageReader.getDestination(ImageReadParam, Iterator<ImageTypeSpecifier>, int, int) line: 2865	
	GIFImageReader.read(int, ImageReadParam) line: 879	
	ImageBanner.readFrame(int, int, ImageReader, int, ImageReadParam) line: 156	
	ImageBanner.readFrames(int, int, ImageInputStream) line: 145	
	ImageBanner.readFrames(int, int) line: 130	
	ImageBanner.printBanner(Environment, PrintStream) line: 103	
	ImageBanner.printBanner(Environment, Class<?>, PrintStream) line: 79	
	SpringApplicationBannerPrinter$Banners.printBanner(Environment, Class<?>, PrintStream) line: 146	
	SpringApplicationBannerPrinter.print(Environment, Class<?>, PrintStream) line: 72	
	SpringApplication.printBanner(ConfigurableEnvironment) line: 561	
	SpringApplication.run(String...) line: 298	
	DemoApplication.main(String[]) line: 31	

I think our best option is to drop the reset code and only call System.setProperty("java.awt.headless", "true"); if the existing property is null. To only other solution I can think of is to render the image using a new classloader that we then throw away.

@philwebb philwebb added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 29, 2021
@philwebb philwebb added this to the 2.5.x milestone Nov 29, 2021
@philwebb philwebb removed the for: team-attention An issue we'd like other members of the team to review label Dec 1, 2021
@philwebb philwebb self-assigned this Dec 1, 2021
@wilkinsona wilkinsona modified the milestones: 2.5.x, 2.6.x May 19, 2022
@wilkinsona wilkinsona modified the milestones: 2.6.x, 2.7.x Nov 24, 2022
@mhalbritter mhalbritter modified the milestones: 2.7.x, 2.7.8 Jan 18, 2023
@mhalbritter
Copy link
Contributor

We now only set this property if not already set.

krenson pushed a commit to krenson/test-push that referenced this issue Mar 15, 2023
…ot-starter-parent from 2.7.7 to 2.7.8 (patch)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [org.springframework.boot:spring-boot-starter-parent](https://spring.io/projects/spring-boot) ([source](https://github.com/spring-projects/spring-boot)) | parent | patch | `2.7.7` -> `2.7.8` |

---

### Release Notes

<details>
<summary>spring-projects/spring-boot</summary>

### [`v2.7.8`](https://github.com/spring-projects/spring-boot/releases/tag/v2.7.8)

[Compare Source](spring-projects/spring-boot@v2.7.7...v2.7.8)

#### ⭐ Noteworthy

-   The coordinates of the MySQL JDBC driver have [changed from `mysql:mysql-connector-java` to `com.mysql:mysql-connector-j`](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes#mysql-jdbc-driver).

#### 🐞 Bug Fixes

-   Devtools sets non-existent property spring.reactor.debug [#&#8203;33858](spring-projects/spring-boot#33858)
-   Failing calls to reactive health indicators are not logged [#&#8203;33774](spring-projects/spring-boot#33774)
-   Failure analysis of NoUniqueBeanDefinitionException reports "defined in null" when bean definition has no resource description [#&#8203;33765](spring-projects/spring-boot#33765)
-   NPE in RabbitProperties when user is given, but password not [#&#8203;33752](spring-projects/spring-boot#33752)
-   SDKMAN should not use repo.spring.io for releases [#&#8203;33708](spring-projects/spring-boot#33708)
-   Homebrew and Scoop should not use repo.spring.io for releases [#&#8203;33702](spring-projects/spring-boot#33702)
-   EndpointRequestMatcher should have a toString method [#&#8203;33690](spring-projects/spring-boot#33690)
-   It is not possible to provide a custom TransactionProvider bean for JOOQ [#&#8203;32899](spring-projects/spring-boot#32899)
-   SpringBootMockResolver causes AopTestUtils.getUltimateTargetObject to recurse until the stack overflows when it calls it with Spring Security's authentication manager bean [#&#8203;32632](spring-projects/spring-boot#32632)
-   Inconsistent discovery of parameter names for selectors in custom actuator endpoints [#&#8203;31240](spring-projects/spring-boot#31240)
-   `@DeprecatedConfigurationProperty` has no effect when declared on a record component's accessor method [#&#8203;29526](spring-projects/spring-boot#29526)
-   Headless mode is forced when banner.\* file is present. [#&#8203;28803](spring-projects/spring-boot#28803)
-   Diagnostics are poor when the JMX port used by the Maven start goal is in use [#&#8203;24044](spring-projects/spring-boot#24044)

#### 📔 Documentation

-   Replace "via" in documentat...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants