GithubHelp home page GithubHelp logo

Utility classes used for several jpaw projects

The classes defined within this repository have been part of the bonaparte java implementation, but in fact do not relate to the DSL and/or serialization / deserialization functionality and therefore have been separated into this repository for better modularity.

Classes which might be useful in other projects are

  • ByteBuilder, a corresponding class to StringBuilder, but for byte arrays
  • ByteArray, a corresponding class to java's String class as implemented in Java 5
  • xenums, enum based classes which allow some kind of inheritance
  • enum sets, with access to the bitmap representation
  • enum sets which are treated as character arrays / strings
  • ApplicationException, some kind of Exception which supports an error number, which can be used to index the messages and categorize the exceptions by core reason.

In addition, this repository serves as a parent pom / bom, defining some revisions of libraries used in other projects.

Building

This project uses maven3 as a build tool. For security reasons, an up to date maven version is enforced (3.8.5 upwards).

The library requires Java 8 minimum, and works with Java 11 and Java 17 as well.

JDP: Java dependency provider - a "no DI" framework

Purpose

JDP intends to be used as a lean alternative to classic dependency injection frameworks such as guice or CDI. It does not attempt to implement a full JSR 330 or 299 standard.

JDP provides the following annotations:

  • Inject (only for xtend) - transparently invokes the provider. @Inject @Any and @Inject @Optional are supported as well.

  • Singleton (scope) - the provider returns the same instance every time

  • Dependent (scope) - the provider returns a new instance every time

  • PerThread (scope) - the provider returns a different instance per thread

  • ScopeWithCustomProvider (scope) - the provider class is specified by the application as an annotation parameter

  • Named (qualifier) - assigns the class to a specific category of implementations

  • Specialized (qualifier) - overrides the implementation of any inherited subclass

  • Alternative (qualifier) - prevents the annotated class to be used unless it is the only one for the category

  • Startup - specifies methods to be invoked at initialization time, in a defined order

JDP offers the following features:

  • Autodetection of classes, as with CDI. No need to code modules as in guice.

  • No need for a no-args constructor. In fact you can create classes with a regular new().

  • No use of proxies as in CDI. This allows you to have final methods and classes.

  • Modifying object resolution at runtime. Fields injected before will continue to have their original value, though.

JDP does not work with cyclic dependencies. I consider that bad design anyway.

How does it work

JDP is intended to be used on Xtend source code. @Inject is an active annotation which provides the annotated field with an initializer, which is just a library call to obtain the desired value. That simple, but sufficient for some of my applications. The xtend portion will be split into a separate project and therefore optional in the next revision.

It offers enough features to replace CDI in some multi-million code line projects. The class repository is kept in a static class however and therefore Jdp should only be used in projects where you provide the main() entry point as well.

Examples

Let's look at some example code. The code is in xtend, which is very similar to Java, and everything except the @Inject will look exactly the same in Java.

package de.jpaw.dp.alternatives

import de.jpaw.dp.Alternative
import de.jpaw.dp.Inject
import de.jpaw.dp.Jdp
import de.jpaw.dp.Singleton
import de.jpaw.dp.Specializes

// definition of an interface. Note that the interface itself is not annotated, same as in guice, CDI etc.
interface Car {
    def void drive();
}

@Alternative
@Singleton
class DumboBuggyShouldNotBeSelected implements Car {
    override drive() {
        println("no, I am an alternative!")
    }
}

@Singleton
class BaseCarShouldNotBeSelected implements Car {
    override drive() {
        println("no, I was overridden!")
    }
}

@Specializes
@Singleton
class MegaCarShouldBeSelected extends BaseCarShouldNotBeSelected {
    override drive() {
        println("I'm driving mega car!")
    }
}

@Alternative
@Singleton
class AnotherDumboBuggyShouldAlsoNotBeSelected implements Car {
    override drive() {
        println("no, I am an alternative!")
    }
}

@Alternative
@Singleton
class SomeCarWhichIsDrivenLater implements Car {
    override drive() {
        println("I'm doing the last round")
    }
}

class MainTestMain {
    def static void main(String [] args) {
        Jdp.init("de.jpaw.dp.alternatives");

        // access from Java code
        Jdp.getRequired(Car).drive();

        // access from xtend
        new SomeOtherClass().driveOtherCar

        // modify the preference
        Jdp.bindClassWithoutQualifier(SomeCarWhichIsDrivenLater, Car)

        // should result in a different one used from now on...
        new SomeOtherClass().driveOtherCar
    }
}


class SomeOtherClass {
    @Inject
    Car myCar

    def void driveOtherCar() {
        myCar.drive
    }
}

Running the code will produce

I'm driving mega car!
I'm driving mega car!
I'm doing the last round

Custom Provider Example

This is a simple example of how a custom scope could be defined.

package de.jpaw.dp.customprovider

import de.jpaw.dp.CustomScope
import de.jpaw.dp.Jdp
import de.jpaw.dp.ScopeWithCustomProvider

interface Activity {
    def void doSomething();
}


// a scope which returns the same instance per day, but a new one the next day.
// for demonstration purposes, it does this for a second instead of a day
// This is for demonstration purposes, the shown class is not thread safe!
class DailyScope implements CustomScope<Activity> {
    private Activity currentActivity = null;
    private long whenSet = -1L;

    // defines the returned activity to be a specific one, from now on...
    override set(Activity instance) {
        currentActivity = instance;
        whenSet = System.currentTimeMillis / 1000
    }

    override close() {
        // hands over resources to GC
        currentActivity = null;
        whenSet = -1;
    }

    override get() {
        val now = System.currentTimeMillis / 1000
        if (currentActivity !== null && whenSet == now) {
            // there is a defined activity, and it was set within this second. Return it.
            return currentActivity
        }
        // create a new activity. Call some factory, or just create a new instance for this simple demo
        whenSet = now
        currentActivity = new Reading();
        return currentActivity
    }
}

@ScopeWithCustomProvider(DailyScope)
class Reading implements Activity {
    private int howOften = 0

    override doSomething() {
        howOften += 1
        println('''I'm reading page «howOften»''')
    }
}


class SimpleCustomScopeDemo {
    def static void main(String [] args) {
        Jdp.init("de.jpaw.dp.customprovider")

        for (var int i = 0; i < 10; i += 1) {
            Jdp.getRequired(Activity).doSomething
            Thread.sleep(300)       // pass some time...
        }
    }
}

Running the code will produce something similar to

I'm reading page 1
I'm reading page 1
I'm reading page 2
I'm reading page 3
I'm reading page 1
I'm reading page 2
I'm reading page 3
I'm reading page 1
I'm reading page 2
I'm reading page 3

Every time page 1 is read, a new instance of the object has been created.

Future Plans and Non-Goals

The following additions are planned:

  • Some file format to allow selection of @Alternatives via configuration file (interface[:qualifier]=implementation)

  • Startup also allowing for instance methods instead of static methods only

  • Shutdown operations to be scheduled by the Startup beans, and executed in reverse order of registration

It is not planned to achieve compatibility to any JSR. There are good existing implementations if you want that, like guice or weld. Therefore all annotations used by Jdp are in a different package on purpose and Jdp does not understand javax.inject.* annotations.

It is also not planned to support injecting objects of a shorter lived scope into a longer one, like a PerThread object into a Singleton. This can only be achieved via proxies, which is exactly one of the key goals of this project to to have any. In such a case, what you really want is to inject a provider, and that is what you should code.

Michael Bischoff's Projects

Michael Bischoff doesn’t have any public repositories yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.