Skip to content

Allow customization of the banner printer used by SpringBootApplication #42284

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

Closed
wants to merge 4 commits into from

Conversation

vjh0107
Copy link
Contributor

@vjh0107 vjh0107 commented Sep 12, 2024

Hello! I’ve made changes to allow the customization of the banner printer.

The Banner class was originally intended for printing a banner programmatically, but I needed a way to customize it more flexibly.
Here is the code before my contribution:

class MyBanner(private val plugin: Plugin) : Banner {
    override fun printBanner(environment: Environment?, sourceClass: Class<*>?, out: PrintStream?) {
        with(plugin.logger) {
            info("██╗  ██╗██╗████████╗")
            info("██║ ██╔╝██║╚══██╔══╝")
            info("█████╔╝ ██║   ██║   ")
            info("██╔═██╗ ██║   ██║   ")
            info("██║  ██╗██║   ██║   ")
            info("╚═╝  ╚═╝╚═╝   ╚═╝   ")
        }
    }
}

So, I changed the printer to be changeable. Now I can create a banner more programmatically!

class MyBanner(private val plugin: Plugin) : Banner {
    override fun printBanner(environment: Environment?, sourceClass: Class<*>?, printStream: PrintStream) {
        with(printStream) {
            println("██╗  ██╗██╗████████╗")
            println("██║ ██╔╝██║╚══██╔══╝")
            println("█████╔╝ ██║   ██║   ")
            println("██╔═██╗ ██║   ██║   ")
            println("██║  ██╗██║   ██║   ")
            println("╚═╝  ╚═╝╚═╝   ╚═╝   ")
        }
    }
}
class MyBannerPrinter(private val plugin: Plugin) : SpringApplicationBannerPrinter {
    override fun print(environment: Environment?, sourceClass: Class<*>?, bannerMode: Banner.Mode): Banner {
        return when (bannerMode) {
            Banner.Mode.CONSOLE -> print(environment, sourceClass, System.out)
            Banner.Mode.LOG -> print(environment, sourceClass, plugin.logger)
            else -> PrintedBanner(getBanner(environment), sourceClass)
        }
    }
}

I tried to follow the existing code style, but if any parts need to be revised, I would appreciate it if you could make corrections.
Thank you!

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 12, 2024
@philwebb
Copy link
Member

@vjh0107 Can you provide some more details about what you're trying to achieve. I'm having a bit of a hard time following the example code you've posted (probably because my Kotlin knowledge isn't that good).

What is the aim of the SpringApplicationBannerPrinter as opposed to the Banner? Does calling SpringApplication.setBanner(...) not work for your needs?

@philwebb philwebb added the status: waiting-for-feedback We need additional information before we can continue label Sep 12, 2024
@vjh0107
Copy link
Contributor Author

vjh0107 commented Sep 12, 2024

@philwebb
The Banner in SpringBoot was designed to focus solely on rendering the Banner itself, without depending on PrintStream, regardless of what PrintStream is used.
However, there was a limitation in extending beyond Console and SpringApplication logger types for PrintStream, so I made it possible to replace the SpringApplicationBannerPrinter. This allows the Banner to focus solely on rendering, while the Printer handles rendering the printed values through PrintStream.
My original code had the issue of being tightly coupled to a logger, printing directly through it instead of using PrintStream for the Banner!

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 12, 2024
@philwebb
Copy link
Member

I'm afraid I'm still not totally following. Perhaps a sample application might help (ideally in Java). Are you saying you want to be able to plug in a different PrintStream for the banner to use? Can you not do that already by having a Banner implementation that ignores the passed in PrintStream and prints to something else?

@vjh0107
Copy link
Contributor Author

vjh0107 commented Sep 12, 2024

That’s right, I’ve already been using it that way, but when someone else uses the banner I already made (or it can be SpringBootBanner), there’s a problem where they can’t set the PrintStream.

@philwebb
Copy link
Member

I wonder if you could use a decorator pattern to do this? I'm not too keen to introduce a new API just for this use-case.

I'm thinking something like:

public class BannerWrapper implements Banner {

    // Fields

    public BannerWrapper(Banner delegate, PrintStream out) {
       this.delegate = delegate;
       this.out = out;
    }

    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
        this.delegate.printBanner(environment, sourceClass, this.out);
    }

}

If that doesn't work, I'd really like to see a sample application so we totally understand the requirements.

@philwebb philwebb added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 12, 2024
@vjh0107
Copy link
Contributor Author

vjh0107 commented Sep 12, 2024

Sadly, the wrapper method doesn’t change only the printing method of the SpringBootBanner.
Here is my sample application that has only changed the way the banner is printed regardless of the banner.

https://github.com/vjh0107/spring-boot-pr-42284

Screenshot 2024-09-13 at 05 42 02

I designed it so that there are no changes to the public API!

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 12, 2024
@philwebb
Copy link
Member

Unfortunately there is new public API which increases the surface area of code we'd need to support. Looking at the sample, I'm afraid I don't see a use-case that will be popular enough for us to warrant the changes. If the decorator approach does not work, the other option you might consider is using the springBootBanner to reprint the banner after the application has started.

Thanks anyway for the suggestion.

@philwebb philwebb closed this Sep 12, 2024
@philwebb philwebb added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged status: feedback-provided Feedback has been provided labels Sep 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants