Giter VIP home page Giter VIP logo

java-service-util's People

Contributors

charphi avatar dependabot-preview[bot] avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

koppor

java-service-util's Issues

Custom service loader

Allow to use a custom service loader such as NetBeans Lookup instead of JDK ServiceLoader.

Shortcut accessor for local immutable instance

Most of the time local immutable instances are called like that: new StuffLoader().get().
There is no need to create a loader in these cases. So the following shortcut could be used instead: StuffLoader.load().

Add generation of batch provider

Having a service ...

@ServiceDefinition(quantifier = Quantifier.MULTIPLE, batch = true)
interface Rule { ... }

..., the following code ...

@ServiceProvider
enum GuidingPrinciples implements Rule { ... }

... would generate

@ServiceProvider
public final class GuidingPrinciplesRuleBatch implements RuleBatch { 
  @Override
  public Stream<Rule> getProviders() {
    return Stream.of(GuidingPrinciples.values());
  } 
}

Type inspection before instantiation

Java 9+ adds the possility to select a provider before instantiating it. This avoids the instantiation of expensive services that would be filtered out during selection.

Provider method workaround for classpath

In Java 9+, a provider method is a public static no-arg method called provider where the return type is the service type.

Since this feature is not available on Java 8, a possible workaround would be to generate a delegate wrapper around this method.

Allow properties as parameter of filter method

Currently, a sorter method has no parameter.
It is possible to filter a service provider with a system property but it uses a static global variable. That global variable makes it difficult to test and prevents some use cases.

It could be interesting to allow a sorter method to have one parameter to inject those properties.

@ServiceDefinition
interface MyService {

  @ServiceFilter
  boolean isAvailable(Properties properties);
}

@ServiceProvider 
class Impl implements MyService {

  @Override
  public boolean isAvailable(Properties properties) {
    return Objects.equals(properties.getProperty("os.name"), "Windows 10");
  }
}

Add ServiceProviderInterface annotation

@ServiceProviderInterface would be a simplified version of @ServiceDefinition with less options and better defaults.

Current issues:

  • #singleton and #mutability usage is confusing
  • there are too many options and some of them are used only in conjunction with others
  • #quantifier is the main option but is not pushed forward clearly to the user
  • custom class loader is not possible
  • the backend mechanism is not flexible
  • some default values are not ideal
  • some combinations of options lead to invalid use cases
  • the processor is difficult to test and maintain due to lot of options combination

Minimum features:

  1. Quantifier
  2. Custom class naming
  3. Batch loading
  4. Preprocessing (filtering/sorting/mapping)
  5. Local caching
  6. Reloading

Additional features:

  1. Custom class loading
  2. Thread safety
  3. Lazy loading

Simplify preprocessor

Preprocessor are functional interfaces. Instances of functional interfaces can be created with lambda expressions, method references or constructor references.

Unfortunatly, annotations do not support this kind of reference. Class references must be used instead and require to write a specific class for each preprocessor.

Catch unexpected exceptions during loading

Unexpected exceptions (aka RuntimeException) can occur during the class initialization, the filtering and the sorting. These exceptions are raised by service providers which should be considered unsafe by default.

The goal is to make the loading safer by catching, logging and recovering from such errors.

Add specialized filter on system property

Allow to filter providers using a system property.

Examples:

  • javax.net.ssl.trustStoreType=Windows-ROOT
  • jdk.tls.disabledAlgorithms=SSLv3, RC4
  • https.cipherSuites=SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,SSL_DHE_DSS_WITH_DES_CBC_SHA

The following code ...

@ServiceDefinition(quantifier = Quantifier.MULTIPLE)
public interface Translator {

    String translate(String text);

    String getName();

    @ServiceFilter
    default boolean isEnabled() {
        return FILTER_ON_PROPERTY.apply(getName());
    }

    static Predicate<String> FILTER_ON_PROPERTY = getFilter("translators", ',', true, true, false);
}

static Predicate<String> getFilter(String key, char separator, boolean onMatch, boolean onMiss, boolean caseSensitive) {
    String property = System.getProperty(key);
    if (property == null) return value -> onMiss;
    String[] values = property.split(String.valueOf(separator), -1);
    return value -> Stream.of(values).anyMatch(caseSensitive ? value::equals : value::equalsIgnoreCase) ^ onMatch;
}

... could be simplified as :

@ServiceDefinition(quantifier = Quantifier.MULTIPLE)
public interface Translator {

    String translate(String text);

    @ServiceFilterOnProperty(key = "translators", separator = ',', onMatch = true, onMiss = true, caseSensitive = false)
    String getName();
}

Add ServiceId annotation

A @ServiceId annotation would specify which method returns the identifier of a service provider. This identifier might be used to filter the providers in a loader through system properties.

Example:

@ServiceDefinition(quantifier = Quantifier.MULTIPLE)
public interface Translator {

    @ServiceId
    String getName();

    String translate(String text);
}

Lazy instantiation

Some service providers might be slow to start and therefore would require lazy loading.

Not sure if this is a good idea because the code will be more complex just for a few specific use cases that can be avoided.

Add explicit declaration of batch class

Batch loading in @ServiceDefinition is specified by the properties batch and batchName. These properties generates a new class.
Example:

@ServiceDefinition ( batch = true, batchName = "a.b.c.SomeBatch" )
interface SomeService { }

A better approach would be to replace these properties by one that specifies the class to use.
Example:

@ServiceDefinition ( batchType = SomeBatch.class )
interface SomeService { }

interface SomeBatch {
  Stream<SomeService > getProviders();
}

Batch loading of providers

Add the possibility to load a bach of providers.

Example:

public interface HelloService {}

@ServiceProvider
public class Impl1 implements HelloService {}

@ServiceProvider
public class Impl2 implements HelloService {}

public class SomeClass {
  @ServiceProviderList
  public Collection<? extends HelloService> getProviders() { ... }
}

Improve error messages on missing directives in module-info

Improve error messages so that problems can be solved with a copy-paste.

Example: replace

Missing module-info.java 'provides' directive for 'demetra.information.InformationExtractor/jdplus.modelling.extractors.ResidualsExtractors.Dynamic'

with

Missing module-info.java directive: 'provides demetra.information.InformationExtractor with jdplus.modelling.extractors.ResidualsExtractors.Dynamic;

And group by service to copy-paste code like:

    provides demetra.information.InformationExtractor with
            jdplus.modelling.extractors.ResidualsExtractors.Dynamic,
            jdplus.modelling.extractors.LikelihoodStatisticsExtractor;

Add ServiceSupport annotation

A ServiceSupport annotation would enforce good pratices when creating service providers.

Example:

@ServiceDefinition
public interface Driver { 

  String getName(); 

  Closeable openConnection();
}

@ServiceSupport
@lombok.Builder ( toBuilder = true )
public final class QuickDriverSupport implements Driver {

  @lombok.Getter
  @lombok.Builder.Default
  private final String name;

  @Override
  public Closeable openConnection() { ... }
}

@ServiceProvider
public final class Driver1 implements Driver {
  @lombok.experimental.Delegate
  private final Driver delegate = QuickDriverSupport.builder().name("X1").build();
}

@ServiceProvider
public final class Driver2 implements Driver {
  @lombok.experimental.Delegate
  private final Driver delegate = QuickDriverSupport.builder().name("X2").build();
}

Add property to customize batch method name

Add property to customize batch method name.
The purpose is to allow a class to implement multiple batch interfaces.

This example:

@ServiceDefinition ( batch=true )
public interface ReaderSpi {}

@ServiceDefinition ( batch=true )
public interface WriterSpi {}

@ServiceProvider
public class BatchReaderImpl implements ReaderSpiBatch {
  Stream<ReaderSpi> getProviders() { ... }
}

@ServiceProvider
public class BatchWriterImpl implements WriterSpiBatch {
  Stream<WriterSpi> getProviders() { ... }
}

Could be replaced with:

@ServiceDefinition ( batch=true, batchMethodName="getReaders" )
public interface ReaderSpi {}

@ServiceDefinition ( batch=true, batchMethodName="getWriters" )
public interface WriterSpi {}

@ServiceProvider ( ReaderSpiBatch.class )
@ServiceProvider ( WriterSpiBatch.class )
public class SomeImpl implements ReaderSpiBatch, WriterSpiBatch  {
  Stream<ReaderSpi> getReaders() { ... }
  Stream<WriterSpi> getWriters() { ... }
}

Another solution would be to customize the method name using the SPI class name:

@ServiceDefinition ( batch=true, autoBatchMethodName=true )
public interface ReaderSpi {}

@ServiceDefinition ( batch=true, autoBatchMethodName=true )
public interface WriterSpi {}

@ServiceProvider ( ReaderSpiBatch.class )
@ServiceProvider ( WriterSpiBatch.class )
public class SomeImpl implements ReaderSpiBatch, WriterSpiBatch  {
  Stream<ReaderSpi> getReaderSpiProviders() { ... }
  Stream<WriterSpi> getWriterSpiProviders() { ... }
}

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.