{"id":19719929,"url":"https://github.com/timboudreau/giulius","last_synced_at":"2025-10-17T13:59:31.273Z","repository":{"id":7894101,"uuid":"9272724","full_name":"timboudreau/giulius","owner":"timboudreau","description":"Tools for loading file-based configuration files and mapping them with Guice's ``@Named`` and more","archived":false,"fork":false,"pushed_at":"2023-07-27T05:30:40.000Z","size":1282,"stargazers_count":18,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-05T19:23:49.210Z","etag":null,"topics":["configuration","guice","injection","lifecycle-management","named"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timboudreau.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-07T06:54:47.000Z","updated_at":"2023-03-18T11:19:10.000Z","dependencies_parsed_at":"2023-01-13T14:32:54.075Z","dependency_job_id":null,"html_url":"https://github.com/timboudreau/giulius","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fgiulius","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fgiulius/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fgiulius/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fgiulius/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timboudreau","download_url":"https://codeload.github.com/timboudreau/giulius/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251585739,"owners_count":21613270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration","guice","injection","lifecycle-management","named"],"created_at":"2024-11-11T23:09:44.204Z","updated_at":"2025-10-17T13:59:31.161Z","avatar_url":"https://github.com/timboudreau.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Giulius\n-------\n\nGiulius (\"julius\") is a collection of several projects for loading configuration files, binding them using Guice and writing boilerplate-free JUnit tests of Guice code.  Read the \n\u003ca href=\"https://timboudreau.com/builds/job/giulius/lastSuccessfulBuild/artifact/giulius/target/site/apidocs/com/mastfrog/giulius/package-summary.html\"\u003ejavadoc here\u003c/a\u003e;  or [scroll down for the tutorial](#introduction--tutorial)\n\nBuilds and a Maven repository containing this project can be \u003ca href=\"https://timboudreau.com/builds/\"\u003e found on timboudreau.com\u003c/a\u003e.\n\n### Features\n\n  * A toolkit for loading Properties files (or URLs) and mapping them with Guice's ``@Named``\n     * Inject configuration values using ``@Named(\"foo\")``\n     * Provide default values using ``@Defaults(\"foo=bar\")`` - processed into files in ``META-INF/settings`` so the system can always function without a configuration file\n     * Override default values in files named ``/etc/defaults.properties``, ``~/defaults.properties``, ``./defaults.properties`` (you can choose the file name or even have multiple files)\n     * Specify the name of the properties file to look in using ``@Namespace`` on the file or package\n     * Defaults can also be loaded from a remote URL\n     * Optionally specify polling interval for reloading configuration from files or URLs\n  * A Maven plugin for merging properties files generated from ``@Defaults``, for building single-JAR applications\n\nThe idea is to make it easy to specify machine-specific configuration for an application in vanilla properties files, and optionally layer up those files to have machine-specific, user-specific and process-specific settings.\n\n## Usage\n--------\n\nAdd the Maven repository \u003ca href=\"https://timboudreau.com/builds/\"\u003ehere\u003c/a\u003e into your build\nfile, and add a dependency \n\n```xml\n        \u003cdependency\u003e\n            \u003cgroupId\u003e${project.groupId}\u003c/groupId\u003e\n            \u003cartifactId\u003egiulius\u003c/artifactId\u003e\n            \u003cversion\u003e1.3.4\u003c/version\u003e \u003c!-- check what the latest version is! --\u003e\n        \u003c/dependency\u003e\n```\n\nNow, say you have a class which needs a value someone might want to change injected into it - annotate it with ``@Defaults`` and a default value that can be overridden.  You can inject\nthese as numbers or strings:\n\n```java\n    @Defaults(\"port=8080\")\n    public class MyServer {\n       private final int port;\n       @Inject\n       public MyServer (@Named(\"port\") int port) {\n          this.port = port;\n       }\n    }\n```\n\nThen ensure defaults are injected.  The easy way is to wrapper the injector in a [Dependencies](https://timboudreau.com/builds/job/giulius/lastSuccessfulBuild/artifact/giulius/target/site/apidocs/com/mastfrog/giulius/Dependencies.html), which offers a few additional useful features (if you don't control injector creation, you can create a Dependencies and call ``createBindings()`` to get a Guice module you can include).\n\n```java\n     Dependencies deps = Dependencies.builder().addDefaultSettings().build();\n     MyServer server = deps.getInstance(MyServer.class);\n```\n\nIf you then create a file named ``defaults.properties`` in the process' working directory or\nyour home directory, and add\n\n    port=8234\n\nThen the value from the annotation will be ignored and this one will be used.  There are many options for affecting what and how and from where settings are loaded - ``defaults.properties``\nis just a default value.\n\n\n## Projects\n\nThe following projects are here:\n\n  * giulius - The core framework that binds ``@Named`` to the contents of properties files, provides builders for Guice injectors and a few other features\n  * giulius-settings - A mini-framework for loading properties from an ordered set of properties files or URLs with properties-format data at the end of it\n  * giulius-tests - The JUnit runner that eliminates boilerplate in setting up unit tests of injected objects\n  * maven-merge-configuration - Merges all ``.properties`` files in ``META-INF/settings`` on the compile classpath into the current project's classes output directory.  Giulius' annotation processor writes files there, but if you want to build a marged executable JAR file, something needs to merge the defaults from all such files.\n\n\n### Credits\n\nMany of the concepts represented here were inspired by (and in some cases, named identically to) mini-frameworks [Eelco Hillenius](https://github.com/chillenious) did when we worked together a few years ago, which were too nice to live without, leading me to build similar things from scratch.\n\n[Greg Bollella](https://www.facebook.com/greg.bollella), of Real-Time Java fame, gets credit for suggesting the name.\n\n### License\n\nMIT License - do what thou wilt, give credit where it's due\n\nIntroduction \u0026 Tutorial\n=======================\n\nThe purpose of these libraries is to make you more productive and to enable\nsoftware to focus on what it's there to do, by removing the need for boilerplate.\nIn the spirit of standing on the shoulders of giants, most of the heavy lifting\nis done by Google's dependency-injection library, [Guice](http://code.google.com/p/google-guice/).\n\nWhat kinds of boilerplate are we eliminating?\n---------------------------------------------\n\n1. *Configuration loading/parsing* - Code should be focused on what it's there to\ndo, but frequently it's necessary to load settings.  This takes the form of a block\nof code, in an otherwise sane class, which parses strings into java primitives, and\nsometimes constructs some sort of object out of the result.\n\n2. *Startup initialiation* - \"plumbing\" code that wires things together and \nintializes things.\n\n3. *Test initialization* - tests usually need to start an environment very similar\nto that of an application, yet different.  Once we've addressed startup initialization,\nit's easy to apply that to tests too.\n\nOn the Value of Tests\n---------------------\n\nI realized after the first draft of this that I was writing as if tests were a\ngood in and of themselves, and perhaps this needs some justification.\n\nIf tests are written after the fact, it is usually seen as a cost, and possibly\nnot a good use of time.  If it is done as part of development, it allows you to\nbuild a system bit by bit, based on parts which you can literally prove work.\nThis means that you find more bugs sooner, and also that you know if some later\nwork is affecting another part of the system in an unanticipated way.  I can't\ncount the number of times in developing these libraries that having a huge test\nsuite has saved me from committing code I thought should work but which had\nsubtle problems.\n\nCode is an investment of time and work.  Tests make it possible to \nkeep that investment.  Code which is covered by tests\nis hard to break with future changes because (with Maven) \nyou know that something is broken as soon as you try to compile.\n\nTests also form an invaluable source of real code that demonstrates how to use\nany API.  If you can guarantee that any feature worth using has tests, then you\nalways know where to go for examples of how to use that feature.\n\nIn the end, the value of tests is easier to experience than to put into words:\nOnce you have the experience of doing doing development where you can simply be\nsure that all the parts you're building on work as advertised, it's hard to \ngo back.\n\nGetting Started\n===============\n\nAssuming you're using [Maven](http://maven.apache.org/), starting to use these\nlibraries is as simple as declaring a dependency on them:\n\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.mastfrog\u003c/groupId\u003e\n            \u003cartifactId\u003egiulius-settings\u003c/artifactId\u003e\n            \u003cversion\u003e1.3.6-SNAPSHOT\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.mastfrog\u003c/groupId\u003e\n            \u003cartifactId\u003egiulius\u003c/artifactId\u003e\n            \u003cversion\u003e1.3.6-SNAPSHOT\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.mastfrog\u003c/groupId\u003e\n            \u003cartifactId\u003egiulius-tests\u003c/artifactId\u003e\n            \u003cversion\u003e1.3.6-SNAPSHOT\u003c/version\u003e\n            \u003cscope\u003etest\u003c/scope\u003e\n        \u003c/dependency\u003e\n\nFor the test code in this document, it's probably simplest to depend on all \nthree.  Check what the latest version is - it was ``1.3.6-SNAPSHOT`` when\nthis document was last updated on 7 May 2013.\n\nUsing Settings\n==============\n\nAny non-trivial application has some configuration.  For simple programs that\nare run from the command-line, it is always preferable for these to be able to\nbe passed in as arguments to the process.\n\nBut libraries need settings too, and they need to come from somewhere.  The\nSettings library solves that problem.\n\nThe main interface to settings is a class called `Settings`.  It is a no-muss,\nno-fuss interface to key/value pairs.\n\n```java\n    public interface Settings extends Iterable\u003cString\u003e {\n        Integer getInt(String name);\n        int getInt(String name, int defaultValue);\n        Long getLong(String name);\n        long getLong(String name, long defaultValue);\n        String getString(String name);\n        String getString(String name, String defaultValue);\n        Boolean getBoolean(String name);\n        boolean getBoolean(String name, boolean defaultValue);\n        Double getDouble(String name);\n        double getDouble(String name, double defaultValue);\n        Set\u003cString\u003e allKeys();\n        Properties toProperties();\n    }\n```\n\nThere are plenty of similar settings interfaces (which can in fact be adaptered\nto ``Settings`` very easily);  the key distinction about Settings is that it\ndoes not have mutator methods.  That doesn't mean the contents of a `Settings` can't\nchange, just that if you want that to happen, the code that does that is probably\nnot the code that also consumes the settings - and if it is, that indicates a \ndesign problem.\n\nNote that ``Settings`` does not do magic:  If you have a setting stored as \"foo\"\nand you call `Settings.getInt` on it, you will get a `NumberFormatException`.\nGenerally these are fail-fast when used with Guice, meaning that if the settings\nare unusable, an `Error` will be thrown early in startup with a meaningful\nmessage.\n\nTypically you don't implement ``Settings``.  You get a ``Settings`` using \na ``SettingsBuilder``.  That class has ways to add properties files, properties\nobjects, other settings objects, and even properties-format text from a \nremote URL.  You can also add environment variables and system properties to the\nset of available settings;  and you can customize values and put them in there\nduring initialization.\n\nHere's a simple example:\n\n```java\n    Settings settings = new SettingsBuilder().addSystemProperties().build();\n    String home = settings.getString(\"user.home\");\n```\n\nThis isn't that exciting, since we've just traded a call to `System.getProperty(\"user.home\")`\nfor a call to `Settings.getString()`.  So what else can you do with Settings?\n\nLayered Settings\n----------------\n\n``SettingsBuilder`` uses a [fluent interface](http://en.wikipedia.org/wiki/Fluent_interface) to\nallow you to stack up multiple sources of settings.  When you call `Settings.get*`,\nthe last one you added is consulted first, followed by the next-to-last, and so forth.\nYou can try this out with some `Properties` objects:\n\n```java\n    Properties a = new Properties();\n    a.setProperty(\"hello\", \"Hello world\");\n    Properties b = new Properties();\n    b.setProperty(\"hello\", \"Goodbye world\");\n\n    Settings settings = new SettingsBuilder().add(a).add(b).build();\n    System.out.println(settings.getString(\"hello\"));\n```\n\nThe result of this code will be the output\n\n    Goodbye world\n\nReading Settings\n----------------\n\nThere wouldn't be much point to settings if they had to be constructed programmatically,\nor you had to manually read them from files, so typically you don't pass \nsettings into a `SettingsBuilder`, you *tell it where it should load them from*.\nThere are several overloaded `add()` methods on `SettingsBuilder` for doing that:\n\n1. `String` adds a string-based path on the classpath (it should not start with a `/`).\nThis tells Settings to look for a file with that name in *every* JAR on the classpath\nand merge them together (if one overrides another, whichever one comes later in\nthe classpath order wins).\n\n2. `File` adds a file (if it exists), causing it to be read as a Java `.properties` file\nusing `Properties.load()`.  Optionally, you can specify an interval for how often the file\nshould be reloaded (so you can have configuration that is dynamic - only do this if you actually need that).\n\n3. `InputStream` reads any input stream you pass in as a properties file.\n\n4. `URL` tries to load a URL as a properties file.  As with File, it can be passed\nan interval after which it should be reloaded.\n\n5. `key, value` allows you to add in a single key/value pair\n\nIn addition, there are several methods which will automatically add all of a \nstandard set of key/value pairs:\n\n - `addEnv()` adds the contents of all environment variables visible to the process as key/value pairs in Settings\n - `addSystemProperties()` adds all system properties\n - `addGeneratedDefaultsFromClasspath()` adds all properties files on the classpath in the location `com/mastfrog/generated-defaults.properties` (*if* the settings builder is using the default namespace - see below)\n - `addDefaultsFromClasspath()` adds all properties files on the classpath in the location `com/mastfrog/defaults.properties`, and any file named `defaults.properties` in the user's home directory (*if* the settings builder is using the default namespace - see below)\n\nFinally, there is simply `SettingsBuilder.createDefault()` which gets you a standard stack of settings which combine system properties, environment variables, defaults files from the classpath and home directories:\n\n        File homeDefaults = new File(new File(System.getProperty(\"user.home\")), \"defaults.properties\");\n        SettingsBuilder b = new SettingsBuilder()\n                .addEnv()\n                .addSystemProperties()\n                .addGeneratedDefaultsFromClasspath()\n                .addDefaultsFromClasspath();\n        if (homeDefaults.exists()) {\n            b = b.add(homeDefaults);\n        }\n\nSo, you take a ``SettingsBuilder`` and build up a Settings object which merges together whatever sources of\nsettings you want;  then you pass that into Giulius ``Dependencies`` to get Guice to bind the values in\nthe settings.\n\nUsing Annotations to Specify Settings\n-------------------------------------\n\nOne of the usual problems with key/value pair settings is that a program is written\nto expect a setting always to exist, but does not handle the case that it is \nsimply not there.  Another typical problem is having a huge file full of settings,\nand having no idea which ones are still used or what classes consume them.\n\nWhat if code which contained a setting actually defined the settings it needs\nand provided a definition of a reasonable default?\n\nWe handle this with the annotation `@Defaults`, like this:\n\n    @Defaults(\"port=8080\",\"baseurl=http://localhost\")\n    public class Server { ...\n\nThis keeps the definition of the setting with the code that uses it;  and additionally, it\ngives us access to settings at compile-time, so they can be sanity checked,\ndocumented or whatever we want.\n\nUsing Namespaces with Settings\n------------------------------\n\nFor legacy code, it may not be enough to provide one blob of keys and values - \nit may have been written to look in a specific place, and that mechanism may need to \ncontinue working for backward compatibility.\n\nFor that purpose, `SettingsBuilder.forNamespace` exists.  What this does is change\nthe default locations it will look in for settings.  So if you call\n\n    Settings s = SettingsBuilder.forNamespace(\"log-service\").createDefault().build();\n\nthen you get a settings which still contains environment variables and system\nproperties, but looks on the classpath in `com/mastfrog/generated-log-service.properties`, `com/mastfrog/log-service.properties` \nand `~/log-service.properties` for default values.  To specify values for these\nnamespaces using the `@Defaults` annotation, do it like this:\n\n    @Defaults(value={\"port=8080\",\"baseurl=http://localhost\"}, namespace=@Namespace(\"log-service\"))\n    public class Server { ...\n\nMutability\n----------\n\nYou may have noticed that the `Settings` interface has no setters - this is\nintentional, as it is almost always a bad idea for code which *consumes* settings\nalso to be able to modify them.\n\nHowever, for legacy code, you can call `SettingsBuilder.createMutable()` to get\na Settings object which can be mutated.  All such settings are in-memory only, and\ndisappear on VM shutdown.  \n\nThis library is about making settings available to an application, with limited\nsupport for settings that are reloaded periodically.  Full-blown support for creating\nand writing files full of settings has different requirements and is an orthagonal\nconcern.\n\n\nGiulius\n=====\n[Guice](http://code.google.com/p/google-guice/) is a dependency injection (DI) tool.\nDepending on whom you talk to, you can get many answers about the purpose of\ndependency injection, such as\n\n - It eliminates the need to call constructors\n - It adds clarity to code because you can see, in any objects constructor arguments,\nall of the objects which it will ever touch\n - It eliminates the threat of ever seeing *uninitialized objects*\n - It means that systems can be decoupled - something that uses a log service \ndoesn't need to know anything about the implementation of it or how to start it\n\nA common pattern in non-DI code is to use static variables for singleton objects.\nTypically there is a static getter which initializes the service, so that the exact\ndetails of how it is initialized are encapsulated;  usually there is a synchronized\nblock so that two callers on different threads do not initialize two instances\nat the same time.\n\n```java\n    public class FooService {\n        private static FooService INSTANCE;\n        public static FooService get() {\n            synchronized (FooService.class);\n               if (INSTANCE == null) {\n                   //...read some files, make an instance here\n               }\n            }\n        }\n        public void doSomething() { ... }\n    }\n```\n\nThis works, but it has some problems:\n\n - There is only one way ``FooService`` can get initialized, and that has to be the\nsame way it is initialized in production. So if ``FooService`` needs a message queue and\na database, then any unit test, no matter how trivial, will need those things\nrunning.  The typical result is that any use of ``FooService`` discourages test writing\nfor all code that calls it - since it makes the code untestable without heroic efforts.  If\n``FooService`` is the heart of the system, it will discourage having tests throughout the whole thing.\n - Synchronizing on every call is not very nice - it will limit paralellism (you could use `volatile` and [double-checked locking](http://en.wikipedia.org/wiki/Double-checked_locking) to eliminate that)\n - It ties every caller directly to the implementation type - the author is forever limited to making FooService be better, and locked out of making a better ``FooService``\n - It gets initialized on a first-come, first-served basis - so it is not at all obvious \nwho initializes it.  And if it is misconfigured, the application may be running for a long\ntime before it shows any sign that something is terribly wrong.\n - We are really stuck with one instance per JVM, without resorting to \nclassloader tricks.  A lot of the time might seem be okay, but it severely limits\nthe ability to test code (easy to write a test that depends on state left behind\nin some global service by a previous test, and spend hours trying to debug why\na test started failing after an unrelated change).  It also limits future flexibility - \nthere might be good reason to run instantiate two totally independent instances in\nthe same VM, and not have them be able to interfere with, or even see each other.\n\nThe typical fix for this problem is to [separate interface and implementation](http://c2.com/cgi/wiki?SeparateInterfacesFromImplementation).  That looks like this:\n\n```java\n    public interface FooService {\n        void doSomething();\n    }\n\n    public class FooServiceImpl implements FooService { ... }\n```\n\nThis gets a lot farther - code that cares about ``FooService`` doesn't need to know\nwhat implements ``FooService`` - it can simply care that there is one.  This helps\na lot - it is now possible to write tests against a toy implementation of \nFooService.  So the codebase is becoming testable.\n\nThere's just one problem:  *Somebody still has to know about FooServiceImpl*.\nSo you code that wants a FooService still has to call `new FooServiceImpl()`.\nWe haven't solved anything at all!\n\nAt this point somebody aware they have a problem makes their first cut at\nsomething like dependency injection:\n\n```java\n    public abstract class FooService {\n        private static FooService INSTANCE;\n        public static synchronized FooService getInstance() {\n            Class\u003c?\u003e type;\n            if (INSTANCE == null) {\n                Class\u003c?\u003e type = Class.forName(System.getProperty(\"fooService\"));\n                if (type == null) { type = DefaultFooService.class; }\n                INSTANCE = (FooService) type.newInstance();\n            }\n            return INSTANCE;\n        }\n    }\n```\n\nNow something or other can set what class to use for `FooService`, and code\nthat uses it doesn't have to know where it comes from.  Something still has\nto set the system property, but at least we can hide `FooServiceImpl` from\nbeing a dependency of everything that uses `FooService`.\n            \nWhat if we could initialize all the things like `FooService` on startup, and\ncode just did not have to worry about where it comes from, if it is initialized,\nor calling some getter that might or might not initialize `FooService`?\n\nWhat if we could find out immediately on startup if `FooService` could not possibly\nrun, and abort startup in time to tell a person what is happening?\n\nThat is the problem (along with the others listed above) which Guice solves.\n\nUsing Guice\n-----------\n\nGuice introduces an invisible phase of application startup, during which services\nwhich are needed at runtime are loaded and instantiated.  It provides a well-defined\nplace to glue together interface and implementation, so that it's guaranteed that\nthere is only *one thing* which needs to know about both.\n\nThere are first-class concepts to know about in Guice:\n\n - `Injector` - a thing which you can ask for instances of classes you need, in\nthe very simple form injector.getInstance(FooService.class);  Guice will take care\nof creating whatever objects are needed to construct an instance.\n - `Module` - a Guice module specifies *bindings* - what implementation to use\nfor what interface.  This takes a form such as\n\n```java\n    bind(FooService.class).to(FooServiceImpl.class);\n```\n\nSo there still is something which knows about both - but it is tucked away in\na Guice module which is seen at startup and never again.  If FooServiceImpl\ntakes some objects in its constructor, Guice will create those if it can.  This\nlooks like this\n\n```java\n    final class FooServiceImpl implements FooService {\n        private final int port;\n        private final LogService logService;\n        @Inject\n        public FooServiceImpl(@Named(\"port\") int port, LogService logService) {\n            this.port = port;\n            this.logService = logService;\n        }\n        ...\n    }\n```\n\nHere we are doing a few things:\n\n - Marking our constructor with `@Inject` to tell Guice it should try to create\nall of the objects it needs\n - Using Guice's `@Named` annotation to say \"I want an integer named 'port'\"\n - Asking for an instance of LogService as well (Guice needs to be able to create it or know where it is too)\n\nAn important thing to remember about Guice is exactly that:  Guice is all\nabout building a graph of objects on startup.  You *can* ask it for objects at\nruntime, but usually you shouldn't.  It's about setting up your dependencies.\nIf you ask Guice to make objects for you after startup, it will work, but this\nis more the [service locator](http://en.wikipedia.org/wiki/Service_locator_pattern)\npattern, *and* it's no longer clear from your constructor what your class uses.\nIf you are writing a framework in its own right, you may legitimately need to\ndo that;  in application code, it's an indication that something is being done wrong.\n\nYou can think of Guice's `Injector` as the repository of all those things which\nused to be held in static variables.\n\nGuice Meets Settings = Giulius\n==============================\n\nIn the last example above, you may have noticed use of the `@Named` annotation.\nWhere did that come from?\n\nWhile the \"keys\" Guice uses to look up objects are (typically) `Class` objects,\nit is routine to need more than one of something.  One of the ways you can solve\nthat is to give names to specific instances of things.\n\nThat can be helpful for all sorts of things:\n\n```java\n    FooService (@Named(\"requests\") Logger requestLogger, @Named(\"debug\") Logger debugLogger) {...}\n```\n\nbut its primary use is for small bits of configuration - the kind of things people\ntypically read from properties files - like the \"port\" number from the earlier \nexample.\n\nWithout a library to help, this is fairly cumbersome, though:\n\n```java\n    bind(Integer.class).annotatedWith(Names.named(\"port\")).toInstance(8080);\n```\n\nand it means some piece of code hard-codes a value that very likely needs to be\nconfigured on a per-machine basis.\n\nThat's where Giulius comes in.  It provides a way to bind all of your key/value\npairs to `@Named` based on the contents of `Settings`.\n\nA class called `Dependencies` wraps Guice's injector and initialization, and\nautomatically binds `@Named` appropriately.  It is a thin layer on top of\nGuice - it just adds one module which does property bindings, and a few other\nuseful application lifecycle utilities.\n\nTo use it, use the `Dependencies` class:\n\n```java\n    Settings settings = SettingsBuilder.createDefault().build();\n    Dependencies deps = new Dependencies(s, moduleA, moduleB, moduleC);\n    //Typically you ask Guice for a single entry-point class;  this bootstraps the rest of the system\n    FooService service = deps.getInstance(FooService.class);\n```\n\nSo, the only difference between this and vanilla Guice usage is that we're using\na Dependencies object instead of talking directly to Guice's injector.  Dependencies\nadds just two things on top of vanilla Guice:\n\n - Binds ``Settings`` key/value pairs to `@Named` and `@Value` automatically\n - Provides for lifecycle management with `ShutdownHookRegistry` - this can be used\nto de-initialize things that would other be memory leaks when the system is logically\nfinished with running, whether or not the VM is actually shutting down (for example,\nthis allows us to *completely* clean up the environment after running one test,\nso that it does not affect the next one, without needing a new VM)\n\nNamespaces\n----------\n\nAbove we mentioned that `SettingsBuilder` can specify \"namespaces\" - logically\nindependent settings objects which load from different places.\n\nWe make this very easy to use with Dependencies, as follows:  In a large application, \noften a subsystem \ndeals with specific configuration just for it.  And particularly with legacy code,\nit may already have configuration loading code that expects that configuration to\nbe isolated from the rest of the system.  You *could* just take all such configuration,\naim it at the same properties file and hope it works - but there can be name collisions,\nand it is probably a better idea to evolve toward that than have it be an all-or-nothing\nproposition.\n\nThis is handled using the `@Namespace` annotation.  *You can annotate either a \nclass or an entire package with `@Namespace`* to change where all uses of \n`@Named` get their values from - to aim it at a specific set of key-value pairs\nwhich might even get its data, initially, from the same file you've already used.\n`Settings.toProperties()` makes it possible to use properties-related code \nunmodified.\n\nMigrating code like this can be accomplished in several phases, and at each\nphase you have code that works:\n\n1. Change the code to take an injected Settings object in its constructor instead of reading\na file;  use `SettingsBuilder.add(File)` to create a `Settings` over the same\nfile you've always used;  use `Settings.toProperties()` initially to leave the\nlegacy code unmodified\n2. Change the code to use a `Settings` object directly\n3. Change the code (if practical) to use `@Named` for settings\n4. If there are commonly used values or reasonable defaults, move them into code\nusing `@Defaults` and delete them from the configuration file\n5. (If desired) Carefully merge the namespaced settings into the global default\nnamespace, ensuring no collisions, and delete the `@Namespaced` annotation \n\n\nWriting Tests with Giulius-Tests\n================================\n\nIt is fairly simple to write standard unit tests with Guice - just use your\n`setUp()` method to do the incantation described above.  It just gets repetitive\nto put this boilerplate in every test.\n\nSo we have a framework for that.  The tests.guice framework allows you to use\nJUnit pretty much the way you are used to, with a simple difference: *your test\nmethods can take arguments*.\n\nThere are three annotations to be concerned with:\n - `@RunWith(GuiceRunner.class)` - annotate your test class with this to tell \nJUnit that you want to use our GuiceRunner to invoke your tests instead of the\nstandard mechanism\n - `@TestWith(ModuleA.class, ModuleB.class)` - you can annotate your test class,\n*or individual test methods* or both, to tell GuiceRunner what modules you need\ninstantiated to set up all the bindings needed to make the objects that are\narguments to your test method.  You can substitute this for the standard JUnit\n`@Test` annotation (if you annotated the class with `@TestWith`) or you can\nannotate the class and just use `@ Test` normally.  You can also use it on both\nthe class and the method if you want some modules used for all test methods, and\nother modules just used for some tests.\n\nModules instantiated with `@TestWith` may either have a no-argument constructor,\nor a single argument of `Settings`.\n\nSo, our tests look pretty similar to ordinary JUnit tests:\n\n```java\n    @TestWith(EncryptionModule.class)\n    public class EncryptorTest extends GuiceTest {\n        @Test\n        public void testPublicKeyEncryption(PublicKeyEncryptor enc) {\n            assertNotNull(enc);\n            String toEncrypt = \"This string will be encrypted, if this goes right\";\n            String encrypted = enc.encryptWithPublicKey(toEncrypt);\n            assertNotNull(encrypted);\n            System.out.println(\"Got \" + encrypted);\n\n            String decrypted = enc.decryptWithPrivateKey(encrypted);\n            assertEquals(toEncrypt, decrypted);\n        }\n    }\n```\n\nexcept that all of the objects and configuration needed to generate key pairs\nor read them from settings are neatly hidden behind Guice - and our test code\ngets to focus on what really matters - the thing it is there to test!\n\nIf your test requires some custom ``Settings``, this is simple - put a properties\nfile with the same name as the text, next to the test on the classpath and it\nwill be loaded before when your tests are run.\n\n``@TestWith`` can be applied to either the _test class_ or or the _test method_\nor both.  And, of course, your test classes can use ``@Inject`` - though in this\nauthor's opinion, parameter injection is preferable.\n\nIf you have a method you want to run immediately after injection, you can annotate\nit with ``@OnInjection``.\n\n#### Advanced Testing Features\n\nSometimes you have more than one implementation of a subsystem which needs to be\ntested, but you want to run more-or-less the same tests on several implementations.\nGiulius-Tests makes it easy to run the same test multiple times with different\nGuice modules - annotate your test\n\n```java\n        @TestWith(value = {TestHarness.Module.class},\n        iterate = {\n            ResourcesApp.ClasspathResourcesModule.class,\n            ResourcesApp.FileResourcesModule.class,\n            ResourcesApp.MergedResourcesModule.class\n        })\n```\n\n[This test](https://github.com/timboudreau/acteur/blob/master/acteur-resources/src/test/java/com/mastfrog/acteur/resources/StaticResourcesTest.java) is a working example of how to do that.\n\nIn fact, if you're slightly insane, you can annotate both the test class and the\ntest method with different ``iterate=`` values, and wind up testing all possible\ncombinations of the sets of modules specified in both annotations (while probably\nnot useful in the real world, there is a test for the test framework that proves that\nit will work correctly if you do it).\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimboudreau%2Fgiulius","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimboudreau%2Fgiulius","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimboudreau%2Fgiulius/lists"}