Bootique is a minimally opinionated platform for modern runnable Java apps.

Overview

build test deploy Maven Central

Bootique is a minimally opinionated java launcher and integration technology. It is intended for building container-less runnable Java applications. With Bootique you can create REST services, webapps, jobs, DB migration tasks, etc. and run them as if they were simple commands. No JavaEE container required! Among other things Bootique is an ideal platform for Java microservices, as it allows you to create a fully-functional app with minimal setup.

Each Bootique app is a collection of modules interacting with each other via dependency injection. This GitHub project provides Bootique core. Bootique team also develops a number of important modules. A full list is available here.

Quick Links

Support

You have two options:

  • Open an issue on GitHub with a label of "help wanted" or "question" (or "bug" if you think you found a bug).
  • Post a question on the Bootique forum.

TL;DR

For the impatient, here is how to get started with Bootique:

  • Declare the official module collection:
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.bootique.bom</groupId>
            <artifactId>bootique-bom</artifactId>
            <version>2.0.M1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency> 
    </dependencies>
</dependencyManagement>
  • Include the modules that you need:
<dependencies>
    <dependency>
        <groupId>io.bootique.jersey</groupId>
        <artifactId>bootique-jersey</artifactId>
    </dependency>
    <dependency>
        <groupId>io.bootique.logback</groupId>
        <artifactId>bootique-logback</artifactId>
    </dependency>
</dependencies>
  • Write your app:
package com.foo;

import io.bootique.Bootique;

public class Application {
    public static void main(String[] args) {
        Bootique
            .app(args)
            .autoLoadModules()
            .exec()
            .exit();
    }
}

It has main() method, so you can run it!

For a more detailed tutorial proceed to this link.

Upgrading

See the "maven-central" badge above for the current production version of bootique-bom. When upgrading, don't forget to check upgrade notes specific to your version.

Comments
  • Errors doesn't help find cause of problem

    Errors doesn't help find cause of problem

    I found that errors with guice most of time not really useful to searching cause of problem, example:

    Exception in thread "main" java.lang.NoClassDefFoundError: io/bootique/application/CommandMetadata
    	at java.lang.Class.getDeclaredMethods0(Native Method)
    	at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    	at java.lang.Class.getDeclaredMethods(Class.java:1975)
    	at com.google.inject.spi.InjectionPoint.getInjectionPoints(InjectionPoint.java:688)
    	at com.google.inject.spi.InjectionPoint.forInstanceMethodsAndFields(InjectionPoint.java:380)
    	at com.google.inject.internal.ConstructorBindingImpl.getInternalDependencies(ConstructorBindingImpl.java:164)
    	at com.google.inject.internal.InjectorImpl.getInternalDependencies(InjectorImpl.java:613)
    	at com.google.inject.internal.InjectorImpl.cleanup(InjectorImpl.java:569)
    	at com.google.inject.internal.InjectorImpl.initializeJitBinding(InjectorImpl.java:555)
    	at com.google.inject.internal.InjectorImpl.createJustInTimeBinding(InjectorImpl.java:884)
    	at com.google.inject.internal.InjectorImpl.createJustInTimeBindingRecursive(InjectorImpl.java:805)
    	at com.google.inject.internal.InjectorImpl.getJustInTimeBinding(InjectorImpl.java:282)
    	at com.google.inject.internal.InjectorImpl.getBindingOrThrow(InjectorImpl.java:214)
    	at com.google.inject.internal.InjectorImpl.getInternalFactory(InjectorImpl.java:890)
    	at com.google.inject.internal.FactoryProxy.notify(FactoryProxy.java:46)
    	at com.google.inject.internal.ProcessedBindingData.runCreationListeners(ProcessedBindingData.java:50)
    	at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:134)
    	at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:107)
    	at com.google.inject.Guice.createInjector(Guice.java:96)
    	at com.google.inject.Guice.createInjector(Guice.java:73)
    	at io.bootique.Bootique.createInjector(Bootique.java:407)
    	at io.bootique.Bootique.createRuntime(Bootique.java:317)
    	at io.bootique.Bootique.run(Bootique.java:342)
    	at com.objectstyle.oc.site.FrontendApplication.main(FrontendApplication.java:39)
    Caused by: java.lang.ClassNotFoundException: io.bootique.application.CommandMetadata
    	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    	... 24 more
    

    I know that one of my modules uses outdated class, but error message don't help me finding such module.

    opened by IRus 8
  • Launching a daemon with access to DI-managed objects on application startup

    Launching a daemon with access to DI-managed objects on application startup

    Hi @andrus , I want to launch a daemon thread on application startup, and I don't want to encapsulate it into a service (it doesn't have a public API). The caveat is that this daemon should have access to Guice-managed services. It seems to me that currently the two options would be:

    1. to manually create BQRuntime and reproduce io.bootique.Bootique#run() in my code
    2. to create a custom Bootique class and to override one of its protected methods (e.g. io.bootique.Bootique#createRuntime(com.google.inject.Injector)) to get direct access to the Injector. Also this would be my only option if I needed something that is described by Key/TypeLiteral, because BQRuntime only lets you get service instances.

    Both options are not very convenient and (1) has a drawback. So I thought I might propose:

    1. adding a static Bootique.run(BQRuntime) method, which will run the provided runtime in "default" Bootique way
    2. adding a BQRuntime.getInjector():Injector method (I personally don't need it atm, but potentially it can be quite useful)

    My code will look like this:

    BQRuntime runtime = Bootique.app(args).autoLoadModules().createRuntime();
    Injector injector = runtime.getInjector();
    // do stuff
    Bootique.run(runtime);
    
    opened by atomashpolskiy 8
  • Environment variables not merged into configuration

    Environment variables not merged into configuration

    Consider that we have the following ServiceFactory in MyModule:

    public class ServiceFactory {
      private boolean foo = true;
      // .. getter and setter
    }
    

    ServiceFactory#foo is true by default, and it's the only configurable option in MyModule, so we don't specify anything in YAML config.

    Then, we set an environment variable BQ_MY_FOO to false.

    Currently the override won't happen, and ServiceFactory#foo will remain true. I suspect this is because of the following:

    1. io.bootique.config.jackson.InPlaceMapOverrider puts MY.FOO into the aggregate configuration -- prefix is in upper-case
    2. io.bootique.config.jackson.JsonNodeConfigurationFactory#findChild looks for properties under my (default config prefix) -- in lower-case
    opened by atomashpolskiy 7
  • Applied skeletal implementation to interface migration automated refactoring

    Applied skeletal implementation to interface migration automated refactoring

    This is a semantics-preserving automated refactoring that migrates existing method implementations in classes to the corresponding implemented interface methods as default methods. The tool does not add new code; it only rearranges existing code.

    • We are evaluating a research prototype automated refactoring Eclipse plug-in called Migrate Skeletal Implementation to Interface. We have applied the tool to your project in the hopes of receiving feedback.
    • The approach is very conservative. That may mean that not all changes that can be made were made. Please feel free to continue the refactoring manually if you wish.
    • We migrated methods declared in both abstract and concrete classes with the hopes of such methods being suitable default methods in corresponding interfaces.
    • The source code should be semantically equivalent to the original.
    • There was one manual change reversal due to an implementation stemming from a unit test that was too test specific.

    Thank you for your help in this evaluation! Any feedback you can provide would be very helpful. In particular, we are interested if each of the proposed changes are helpful or not.

    opened by khatchad 7
  • Cleaning up APIs deprecated since <= 0.25

    Cleaning up APIs deprecated since <= 0.25

    We are approaching 1.0 beta, so need to get aggressive removing deprecated features before we freeze the API. So going to remove everything currently deprecated in the core and across modules.

    UPGRADE NOTES

    The most notable changethat you will not notice just by recompiling, is that Bootique now completely ignores BQ_ environment variables that used to set config properties. Please inspect your app launch environment (be it IDE or server/Docker/cloud) to see if you still rely on such variables. Switch to explicitly declared variables instead:

    // FWIW, you can use your old BQ_ var name here if you feel like it. 
    // Just need to bind it explicitly.
    BQCoreModule.extend(bidner).declareVar("a.b.c", "MY_VAR");
    
    opened by andrus 6
  • Way to override JacksonService

    Way to override JacksonService

    I'd like to change implementation of JacksonService. I want to do it, because it's only way to pass modules to jackson's ObjectMapper which used for config parsing.

    opened by IRus 6
  • (Help Wanted)

    (Help Wanted)

    Hello, When starting Bootique on eclipse (Mac OS X) following the getting started on the io.bootique website, I've got the following error :

    1. Error in custom provider, java.lang.IllegalStateException: Unable to acquire the logger context at io.bootique.logback.LogbackModule.provideRootLogger(LogbackModule.java:61) while locating ch.qos.logback.classic.Logger for the 1st parameter of io.bootique.logback.LogbackModule$LogInitTrigger.(LogbackModule.java:68) at io.bootique.logback.LogbackModule.configure(LogbackModule.java:52) while locating io.bootique.logback.LogbackModule$LogInitTrigger

    My pow.xml is : 4.0.0 com.factory chatbootique 0.0.1-SNAPSHOT ChatBootique

    io.bootique.jersey bootique-jersey 1.1 io.bootique.logback bootique-logback 1.1 io.agrest agrest 3.0 org.apache.cayenne cayenne-server 4.1.RC2

    And my main class is : public class ChatMain implements Module {

    public static void main(String[] args) {
    	
    	Module module = binder -> JerseyModule.extend(binder).addResource(ChatApi.class);
    	
    	Bootique.app("--config=classpath:myConfig.yml", "--server").autoLoadModules().module(module).exec().exit();
    }
    
    public void configure(Binder binder) {
    	JerseyModule.extend(binder);
    }
    

    }

    opened by jebadero 5
  • Default value for options

    Default value for options

    For example I define simple command with default value for command option:

    class TestCommandDefaultOption extends CommandWithMetadata {
        public final static String OPT = "opt";
    
        public TestCommandDefaultOption() {
            super(CommandMetadata.builder("testCommandDefaultOption")
                    .addOption(OptionMetadata.builder(OPT).defaultValue("optValue").build()));
        }
    
        @Override
        public CommandOutcome run(Cli cli) {
            return CommandOutcome.succeeded();
        }
    }
    

    I expecting that if I'm not pass any value for option opt I will get optValue for cli.optionString call, but instead I got null.

    bug 
    opened by IRus 5
  • Complex command invocation structures

    Complex command invocation structures

    Relates to #131. This PR is not for merging, but rather for preliminary review. It's still rough on edges and needs more work, but the overall idea should be clear. There's also a simple test, that demonstrates the user-facing API: io.bootique.Bootique_CommandOverrideIT.

    opened by atomashpolskiy 5
  • Update Jackson to 2.9.5

    Update Jackson to 2.9.5

    We have outdated version of jackson - 2.9.0. A lot of libraries already using new versions of jackson(typically 2.8, since 2.9 fresh version) so I think we need to update jackson.

    opened by IRus 5
  • Declare dependencies in the standard modules

    Declare dependencies in the standard modules

    Per #183 we are allowing modules to optionally declare dependencies. This is very helpful in unit tests when we are assembling partial stacks and would prefer not to use "autoLoadModules". So let's declare explicit dependencies across all standard Bootique modules.

    opened by andrus 4
  • Declared vars not matching an existing config path are excluded from help

    Declared vars not matching an existing config path are excluded from help

    This was initially described in #292. Declared variables that pointed to an invalid path were excluded from help. This may actually be the correct behavior, but we need to notify the user somehow about misconfiguration (via logs, or via special messages in the help attached to those vars)

    opened by andrus 0
  • "bootique-di" overrides handling

    With "bootique-di" module override behavior has changed compared to Guice. I'd like to document it here so that there's a record of the status quo, as well a something for us to analyze and decide if we want to change / improve something going forward.

    Guice / Bootique 1.x overriding behavior

    • Overrides are rare (composition with MapBinder and Multibinder is preferred).
    • Bootique hides the Guice override API. It allows to define module "override" relationships either via BQModuleProvider.overrides() via Bootoque.override(..). This is passed to Guice internally (Modules.override(M1.class).with(M2.class)). The underlying override graph resolution is done by Guice.
    • If there are two services for a given DI key defined in two different modules, Guice will throw an exception unless one module is declared to override another

    Bootique 2.0 behavior

    • (same) Overrides are rare (composition with MapBuilder and SetBuilder is preferred).
    • (somewhat similar) Bootique allows to define module "override" relationships either via BQModuleProvider.overrides() via Bootoque.override(..). This affects module load order (see next item for why this is relevant).
    • (different) If there are two services for a given DI key defined in two different modules, the one that was loaded last takes precedence. So defining overrides helps with the correct module load order. If override rules are not explicitly declared, override is still allowed. Which service is loaded will depend on the de-facto order of modules that is not transparent to the user.

    Where do we want to take this

    So in 2.0 override policies are more like suggestions instead of hard rules. This behavior is both more flexible and more error-prone. We can either keep the things the way they are, or attempt to make them smarter (either throw an exception or print a warning on an undeclared override). For this we need to have a connection between a service and its module. We don't have this information now, but should be easy to add.

    opened by andrus 0
  • Help wanted for getting scalar configuration variable values for replacing placeholders

    Help wanted for getting scalar configuration variable values for replacing placeholders

    I use the bootique flyway module to execute database migrations for 4 schemas (and 4 different locations) after each other and I want to minimise the number of scripts.

    My idea:

    1. Invoke the bootique job module with a YAML to execute 4 Flyway jobs in order AND with a YAML defining the placeholders variables
    2. Each job has several parameters: database schema, Flyway YAML config file and Flyway command (info, migrate, etcetera).
    3. I create a temporary config file using Apache commons string substitution.
    4. The job invokes the Bootique.app with a new command line including the temporary config file and the Flyway command.

    So I have a Flyway YAML configuration file that starts like:

    jdbc: oracle: url: jdbc:oracle:thin:@//${db.host}:${db.port}/${db.service} driverClassName: oracle.jdbc.OracleDriver username: ${db.username} password: ${db.password}

    The variables are in another YAML file:

    db: host: 127.0.0.1 port: 1526 service: ORCL username: SCOTT password: TIGER

    I am having problems with step 3. I have no idea how to get the values for each "db." variable. And I prefer not to use Java system properties, at least not on the first command line invocation.

    opened by gpaulissen 2
  • BQCoreModuleExtender.setProperty causes ArrayIndexOutOfBoundsException for multiple array indices

    BQCoreModuleExtender.setProperty causes ArrayIndexOutOfBoundsException for multiple array indices

    A bug... Assuming a.array is an empty array in configuration, you can populate it via setProperty:

    BQCoreModule.extender(b)
        .property("bq.a.array[0]", "J")
        .property("bq.a.array[1]", "A")
        .property("bq.a.array[2]", "Z")
    

    This often throws ArrayIndexOutOfBoundsException, because property names are stored in a map internally and are applied out of order (so addition to the index "2" may happen before index "0"). Other times it works, if the order is coincidentally correct.

    bug 
    opened by andrus 1
  • API to suppress module options

    API to suppress module options

    We already allow to explicitly suppress module commands:

    BQModuleProvider commands = Commands
         .builder(HelpCommand.class, HelpConfigCommand.class)
         .noModuleCommands()
         .build();
    

    Would be also useful to suppress module options. E.g. Liquibase module defines both commands and standalone options. And turning off commands (when running LB via a custom command), but not options leaves the app in a confusing state.

    There may be a similar API for Options:

    BQModuleProvider commands = Options
         .builder(CliConfigurationSource.configOption())
         .noModuleOptions()
         .addOption("o1")
         .addOption(OptionMetadata.builder("o2").build())
         .build();
    

    It will deal solely with options added at the top level. Command-related option set should be driven by whatever commands are active in the system. I.e. command-provided options should stay active no matter whether noModuleOptions is on or off. This includes options for a default command. Also Command-provided options should only include options for active commands.

    opened by andrus 0
Owner
Bootique Project
Bootique is a minimally opinionated platform for modern runnable Java apps
Bootique Project
Vaadin 6, 7, 8 is a Java framework for modern Java web applications.

Vaadin Framework Vaadin allows you to build modern web apps efficiently in plain Java, without touching low level web technologies. This repository co

Vaadin 1.7k Jan 5, 2023
An evolving set of open source web components for building mobile and desktop web applications in modern browsers.

Vaadin components Vaadin components is an evolving set of high-quality user interface web components commonly needed in modern mobile and desktop busi

Vaadin 519 Dec 31, 2022
A Java Framework for Building Bots on Facebook's Messenger Platform.

Racter A Java Framework for Building Bots on Facebook's Messenger Platform. Documentation Installation To add a dependency using Maven, use the follow

Ahmed 18 Dec 19, 2022
CUBA Platform is a high level framework for enterprise applications development

Java RAD framework for enterprise web applications Website | Online Demo | Documentation | Guides | Forum CUBA Platform is a high level framework for

CUBA Platform 1.3k Jan 1, 2023
Ninja is a full stack web framework for Java. Rock solid, fast and super productive.

_______ .___ _______ ____. _____ \ \ | |\ \ | | / _ \ / | \| |/ | \ | |/ /_\ \ / | \

Ninja Web Framework 1.9k Jan 5, 2023
The modular web framework for Java and Kotlin

∞ do more, more easily Jooby is a modern, performant and easy to use web framework for Java and Kotlin built on top of your favorite web server. Java:

jooby 1.5k Dec 16, 2022
Apache Wicket - Component-based Java web framework

What is Apache Wicket? Apache Wicket is an open source, java, component based, web application framework. With proper mark-up/logic separation, a POJO

The Apache Software Foundation 657 Dec 31, 2022
Micro Java Web Framework

Micro Java Web Framework It's an open source (Apache License) micro web framework in Java, with minimal dependencies and a quick learning curve. The g

Pippo 769 Dec 19, 2022
True Object-Oriented Java Web Framework

Project architect: @paulodamaso Takes is a true object-oriented and immutable Java8 web development framework. Its key benefits, comparing to all othe

Yegor Bugayenko 748 Dec 23, 2022
ZK is a highly productive Java framework for building amazing enterprise web and mobile applications

ZK ZK is a highly productive Java framework for building amazing enterprise web and mobile applications. Resources Documentation Tutorial ZK Essential

ZK 375 Dec 23, 2022
An Intuitive, Lightweight, High Performance Full Stack Java Web Framework.

mangoo I/O mangoo I/O is a Modern, Intuitive, Lightweight, High Performance Full Stack Java Web Framework. It is a classic MVC-Framework. The foundati

Sven Kubiak 52 Oct 31, 2022
Java Web Toolkit

What is JWt ? JWt is a Java library for developing web applications. It provides a pure Java component-driven approach to building web applications, a

null 48 Jul 16, 2022
A simple expressive web framework for java. Spark has a kotlin DSL https://github.com/perwendel/spark-kotlin

Spark - a tiny web framework for Java 8 Spark 2.9.3 is out!! Changeset <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</a

Per Wendel 9.4k Dec 29, 2022
A web MVC action-based framework, on top of CDI, for fast and maintainable Java development.

A web MVC action-based framework, on top of CDI, for fast and maintainable Java development. Downloading For a quick start, you can use this snippet i

Caelum 347 Nov 15, 2022
Tiny, easily embeddable HTTP server in Java.

NanoHTTPD – a tiny web server in Java NanoHTTPD is a light-weight HTTP server designed for embedding in other applications, released under a Modified

NanoHttpd 6.5k Jan 1, 2023
This is a Playwright Java Framework written in POM

Playwright Java Framework Main Objective of this Framework is to Build an Automation Framework that can be scalable, Easily Configurable and Ready to

AutoInfra 11 Oct 17, 2022
应用分身、模拟设备、模拟wifi、虚拟多开、钉钉打卡、企微打卡、插件开发、XP插件、模拟用户操作、java hook、c++ hook

VirtualApp11 original software This project is only for your use, please have any questions Wechat : serven_scorpion Email : [email protected] Teleg

ServenScorpion 395 Dec 26, 2022
A server-state reactive Java web framework for building real-time user interfaces and UI components.

RSP About Maven Code examples HTTP requests routing HTML markup Java DSL Page state model Single-page application Navigation bar URL path UI Component

Vadim Vashkevich 33 Jul 13, 2022