diff --git a/CHANGELOG.md b/CHANGELOG.md index e96636b93..242f8f2e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Version 3.8.5 (2019-03-22) + +* [new] The `@Provide` annotation allows to register JSR-330 providers for producing injectable instances of a specific type. + # Version 3.8.4 (2019-03-12) * [fix] Fix Jansi loading on unsupported platforms. diff --git a/cli/pom.xml b/cli/pom.xml index 63b3cf3c8..76cdcd108 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-cli diff --git a/core/pom.xml b/core/pom.xml index fd769080e..daa911e84 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-core diff --git a/core/src/main/java/org/seedstack/seed/core/internal/Bindable.java b/core/src/main/java/org/seedstack/seed/core/internal/Bindable.java new file mode 100644 index 000000000..aa38d95fd --- /dev/null +++ b/core/src/main/java/org/seedstack/seed/core/internal/Bindable.java @@ -0,0 +1,38 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.seed.core.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.inject.Binder; +import java.lang.annotation.Annotation; +import java.util.Optional; +import javax.inject.Qualifier; +import org.seedstack.shed.reflect.AnnotationPredicates; +import org.seedstack.shed.reflect.Annotations; + +abstract class Bindable { + final Class target; + final Annotation qualifier; + + Bindable(Class target) { + this.target = checkNotNull(target, "Binding target should not be null"); + this.qualifier = findQualifier(this.target).orElse(null); + } + + abstract void apply(Binder binder); + + private Optional findQualifier(Class target) { + return Annotations.on(target) + .traversingSuperclasses() + .traversingInterfaces() + .findAll() + .filter(AnnotationPredicates.annotationAnnotatedWith(Qualifier.class, false)) + .findFirst(); + } +} diff --git a/core/src/main/java/org/seedstack/seed/core/internal/BindingDefinition.java b/core/src/main/java/org/seedstack/seed/core/internal/BindingDefinition.java index ac315b5b3..704d91d45 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/BindingDefinition.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/BindingDefinition.java @@ -5,69 +5,47 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.seedstack.seed.core.internal; -import static com.google.common.base.Preconditions.checkNotNull; +package org.seedstack.seed.core.internal; import com.google.inject.Binder; import com.google.inject.binder.AnnotatedBindingBuilder; -import java.lang.annotation.Annotation; -import java.util.Optional; -import javax.inject.Qualifier; import org.seedstack.seed.SeedException; -import org.seedstack.shed.reflect.AnnotationPredicates; -import org.seedstack.shed.reflect.Annotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BindingDefinition { +class BindingDefinition extends Bindable { private static final Logger LOGGER = LoggerFactory.getLogger(BindingDefinition.class); - private final Class key; - private final Class target; - private final Annotation qualifier; - - public BindingDefinition(Class target) { - this(target, null); - } + private final Class from; - public BindingDefinition(Class target, Class fromKey) { - this.target = checkNotNull(target, "Binding target should not be null"); - this.key = fromKey; - this.qualifier = findQualifier(this.target).orElse(null); + BindingDefinition(Class target, Class from) { + super(target); + this.from = from; } public void apply(Binder binder) { - if (key != null) { - AnnotatedBindingBuilder bind = binder.bind(key); - if (!key.isAssignableFrom(target)) { + if (from != null) { + AnnotatedBindingBuilder bind = binder.bind(from); + if (!from.isAssignableFrom(target)) { throw SeedException.createNew(CoreErrorCode.INVALID_BINDING) - .put("key", key) + .put("key", from) .put("target", target); } if (qualifier != null) { - LOGGER.trace("Binding {} annotated with {} to {}", key.getName(), qualifier, target.getName()); - bind.annotatedWith(qualifier).to(getExtendingClass(target)); + LOGGER.debug("Binding {} annotated with {} to {}", from.getName(), qualifier, target.getName()); + bind.annotatedWith(qualifier).to(target); } else { - LOGGER.trace("Binding {} to {}", key.getName(), target.getName()); - bind.to(getExtendingClass(target)); + LOGGER.debug("Binding {} to {}", from.getName(), target.getName()); + bind.to(target); } } else { - LOGGER.trace("Binding {} to itself", target.getName()); - binder.bind(target); + if (qualifier != null) { + LOGGER.debug("Binding {} annotated with {} to itself", target.getName(), qualifier); + binder.bind(target).annotatedWith(qualifier); + } else { + LOGGER.debug("Binding {} to itself", target.getName()); + binder.bind(target); + } } } - - private Optional findQualifier(Class target) { - return Annotations.on(target) - .traversingSuperclasses() - .traversingInterfaces() - .findAll() - .filter(AnnotationPredicates.annotationAnnotatedWith(Qualifier.class, false)) - .findFirst(); - } - - @SuppressWarnings("unchecked") - private > C getExtendingClass(Class aClass) { - return (C) aClass; - } } diff --git a/core/src/main/java/org/seedstack/seed/core/internal/CoreModule.java b/core/src/main/java/org/seedstack/seed/core/internal/CoreModule.java index b23ecf1e3..24e28ab7f 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/CoreModule.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/CoreModule.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal; import com.google.inject.AbstractModule; @@ -17,10 +18,10 @@ class CoreModule extends AbstractModule { private final Logger LOGGER = LoggerFactory.getLogger(CoreModule.class); private final Collection modules; - private final Set bindings; + private final Set bindings; private final boolean overriding; - CoreModule(Collection modules, Set bindings, boolean overriding) { + CoreModule(Collection modules, Set bindings, boolean overriding) { this.modules = modules; this.bindings = bindings; this.overriding = overriding; diff --git a/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java b/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java index 83f50c19b..05bfd9430 100644 --- a/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java +++ b/core/src/main/java/org/seedstack/seed/core/internal/CorePlugin.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core.internal; import com.google.common.base.Strings; @@ -16,6 +17,7 @@ import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; +import javax.inject.Provider; import org.kametic.specifications.Specification; import org.seedstack.seed.core.internal.utils.SpecificationBuilder; import org.seedstack.shed.reflect.Classes; @@ -32,10 +34,12 @@ public class CorePlugin extends AbstractSeedPlugin { InstallResolver.INSTANCE).build(); private static final Specification> bindSpecification = new SpecificationBuilder<>( BindResolver.INSTANCE).build(); + private static final Specification> providerSpecification = new SpecificationBuilder<>( + ProvideResolver.INSTANCE).build(); private final Set> modules = new HashSet<>(); private final Set> overridingModules = new HashSet<>(); - private final Set bindings = new HashSet<>(); - private final Set overridingBindings = new HashSet<>(); + private final Set bindings = new HashSet<>(); + private final Set overridingBindings = new HashSet<>(); @Override public String name() { @@ -52,10 +56,10 @@ public Collection classpathScanRequests() { return classpathScanRequestBuilder() .specification(installSpecification) .specification(bindSpecification) + .specification(providerSpecification) .build(); } - @SuppressWarnings("unchecked") @Override public InitState initialize(InitContext initContext) { String autodetectModules = initContext.kernelParam(AUTODETECT_MODULES_KERNEL_PARAM); @@ -65,6 +69,7 @@ public InitState initialize(InitContext initContext) { String autodetectBindings = initContext.kernelParam(AUTODETECT_BINDINGS_KERNEL_PARAM); if (Strings.isNullOrEmpty(autodetectBindings) || Boolean.parseBoolean(autodetectBindings)) { detectBindings(initContext); + detectProviders(initContext); } return InitState.INITIALIZED; } @@ -101,6 +106,18 @@ private void detectBindings(InitContext initContext) { })); } + @SuppressWarnings("unchecked") + private void detectProviders(InitContext initContext) { + initContext.scannedTypesBySpecification().get(providerSpecification) + .forEach(candidate -> ProvideResolver.INSTANCE.apply(candidate).ifPresent(annotation -> { + if (annotation.override()) { + overridingBindings.add(new ProviderDefinition<>((Class>) candidate)); + } else { + bindings.add(new ProviderDefinition<>((Class>) candidate)); + } + })); + } + @Override public Object nativeUnitModule() { return new CoreModule( diff --git a/core/src/main/java/org/seedstack/seed/core/internal/ProvideResolver.java b/core/src/main/java/org/seedstack/seed/core/internal/ProvideResolver.java new file mode 100644 index 000000000..98ed896d2 --- /dev/null +++ b/core/src/main/java/org/seedstack/seed/core/internal/ProvideResolver.java @@ -0,0 +1,20 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.seedstack.seed.core.internal; + +import org.seedstack.seed.Provide; +import org.seedstack.shed.reflect.StandardAnnotationResolver; + +class ProvideResolver extends StandardAnnotationResolver, Provide> { + static ProvideResolver INSTANCE = new ProvideResolver(); + + private ProvideResolver() { + // no external instantiation allowed + } +} diff --git a/core/src/main/java/org/seedstack/seed/core/internal/ProviderDefinition.java b/core/src/main/java/org/seedstack/seed/core/internal/ProviderDefinition.java new file mode 100644 index 000000000..3cd677dc5 --- /dev/null +++ b/core/src/main/java/org/seedstack/seed/core/internal/ProviderDefinition.java @@ -0,0 +1,51 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.seed.core.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.inject.Binder; +import com.google.inject.TypeLiteral; +import com.google.inject.binder.AnnotatedBindingBuilder; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import javax.inject.Provider; +import net.jodah.typetools.TypeResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class ProviderDefinition> extends Bindable

{ + private static final Logger LOGGER = LoggerFactory.getLogger(ProviderDefinition.class); + private final Type from; + + ProviderDefinition(Class

provider) { + super(provider); + Type type = checkNotNull(TypeResolver.resolveGenericType(Provider.class, provider), + "Unable to resolve generic type of provider " + provider.getName()); + if (type instanceof ParameterizedType) { + from = ((ParameterizedType) type).getActualTypeArguments()[0]; + } else { + throw new IllegalArgumentException("A generic type is required for provider " + provider.getName()); + } + } + + @SuppressWarnings("unchecked") + public void apply(Binder binder) { + AnnotatedBindingBuilder bind = binder.bind((TypeLiteral) TypeLiteral.get(from)); + if (qualifier != null) { + LOGGER.debug("Binding {} annotated with {} to provider {}", + from.getTypeName(), + qualifier, + target.getName()); + bind.annotatedWith(qualifier).toProvider(target); + } else { + LOGGER.debug("Binding {} to provider {}", from.getTypeName(), target.getName()); + bind.toProvider(target); + } + } +} diff --git a/core/src/test/java/custom/CustomApplicationProvider.java b/core/src/test/java/custom/CustomApplicationProvider.java new file mode 100644 index 000000000..479fad557 --- /dev/null +++ b/core/src/test/java/custom/CustomApplicationProvider.java @@ -0,0 +1,74 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package custom; + +import java.io.File; +import java.util.Map; +import javax.inject.Provider; +import org.seedstack.coffig.Coffig; +import org.seedstack.seed.Application; +import org.seedstack.seed.ClassConfiguration; +import org.seedstack.seed.Provide; + +@Provide(override = true) +public class CustomApplicationProvider implements Provider { + @Override + public Application get() { + return new Application() { + @Override + public String getName() { + return "custom"; + } + + @Override + public String getId() { + return null; + } + + @Override + public String getVersion() { + return null; + } + + @Override + public File getStorageLocation(String context) { + return null; + } + + @Override + public boolean isStorageEnabled() { + return false; + } + + @Override + public Coffig getConfiguration() { + return null; + } + + @Override + public ClassConfiguration getConfiguration(Class someClass) { + return null; + } + + @Override + public String substituteWithConfiguration(String value) { + return null; + } + + @Override + public Map getKernelParameters() { + return null; + } + + @Override + public String[] getArguments() { + return new String[0]; + } + }; + } +} diff --git a/core/src/test/java/org/seedstack/seed/core/CorePluginIT.java b/core/src/test/java/org/seedstack/seed/core/CoreIT.java similarity index 88% rename from core/src/test/java/org/seedstack/seed/core/CorePluginIT.java rename to core/src/test/java/org/seedstack/seed/core/CoreIT.java index 74aae17eb..814fecbcf 100644 --- a/core/src/test/java/org/seedstack/seed/core/CorePluginIT.java +++ b/core/src/test/java/org/seedstack/seed/core/CoreIT.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed.core; import static org.assertj.core.api.Assertions.assertThat; @@ -31,6 +32,7 @@ import org.seedstack.seed.core.fixtures.DummyService1; import org.seedstack.seed.core.fixtures.DummyService2; import org.seedstack.seed.core.fixtures.DummyService3; +import org.seedstack.seed.core.fixtures.ProvidedInterface; import org.seedstack.seed.core.fixtures.Service; import org.seedstack.seed.core.fixtures.Service1; import org.seedstack.seed.core.fixtures.Service2; @@ -43,7 +45,7 @@ import some.other.pkg.ForeignClass; @RunWith(SeedITRunner.class) -public class CorePluginIT { +public class CoreIT { @Inject private Injector injector; @@ -118,6 +120,14 @@ public void explicitBindingsAreWorking() { BoundOverrideFromInterfaceWithAnnotation.class); } + @Test + public void explicitProvidedBindingsAreWorking() { + HolderNominal holder = injector.getInstance(HolderNominal.class); + assertThat(holder.providedFromInterface).isInstanceOf(ProvidedInterface.class); + assertThat(holder.providedFromInterfaceWithName).isInstanceOf(ProvidedInterface.class); + assertThat(holder.providedFromInterfaceWithAnnotation).isInstanceOf(ProvidedInterface.class); + } + @Bind private static class LoggerHolder { private static final Logger logger = LoggerFactory.getLogger(LoggerHolder.class); @@ -170,6 +180,14 @@ private static class HolderNominal { @Inject @Dummy BoundInterface boundFromInterfaceWithAnnotation; + @Inject + ProvidedInterface providedFromInterface; + @Inject + @Named("toto") + ProvidedInterface providedFromInterfaceWithName; + @Inject + @Dummy + ProvidedInterface providedFromInterfaceWithAnnotation; } private static class HolderException { diff --git a/core/src/test/java/org/seedstack/seed/core/OverrideSeedStackIT.java b/core/src/test/java/org/seedstack/seed/core/OverrideSeedStackIT.java new file mode 100644 index 000000000..2bf38fa32 --- /dev/null +++ b/core/src/test/java/org/seedstack/seed/core/OverrideSeedStackIT.java @@ -0,0 +1,37 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.seedstack.seed.core; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.inject.Inject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.seedstack.seed.Application; +import org.seedstack.seed.testing.LaunchMode; +import org.seedstack.seed.testing.LaunchWith; +import org.seedstack.seed.testing.SystemProperty; +import org.seedstack.seed.testing.junit4.SeedITRunner; + +@RunWith(SeedITRunner.class) +@LaunchWith(mode = LaunchMode.PER_TEST) +public class OverrideSeedStackIT { + @Inject + private Application application; + + @Test + public void normalApplicationIsInjectable() { + assertThat(application.getName()).isEqualTo("seed-it"); + } + + @Test + @SystemProperty(name = "additionalPackage", value = "custom") + public void customApplicationIsInjectable() { + assertThat(application.getName()).isEqualTo("custom"); + } +} diff --git a/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterface.java b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterface.java new file mode 100644 index 000000000..1fb37b10d --- /dev/null +++ b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterface.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.seedstack.seed.core.fixtures; + +import javax.inject.Provider; +import org.seedstack.seed.Provide; + +@Provide +public class ProvidedFromInterface implements Provider> { + @Override + public ProvidedInterface get() { + return new Impl(); + } + + private static class Impl implements ProvidedInterface { + + } +} diff --git a/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterfaceWithAnnotation.java b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterfaceWithAnnotation.java new file mode 100644 index 000000000..efc76244d --- /dev/null +++ b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterfaceWithAnnotation.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.seedstack.seed.core.fixtures; + +import javax.inject.Provider; +import org.seedstack.seed.Provide; + +@Provide +@Dummy +public class ProvidedFromInterfaceWithAnnotation implements Provider> { + @Override + public ProvidedInterface get() { + return new Impl(); + } + + private static class Impl implements ProvidedInterface { + + } +} diff --git a/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterfaceWithName.java b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterfaceWithName.java new file mode 100644 index 000000000..c30ad9b44 --- /dev/null +++ b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedFromInterfaceWithName.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.seedstack.seed.core.fixtures; + +import javax.inject.Named; +import javax.inject.Provider; +import org.seedstack.seed.Provide; + +@Provide +@Named("toto") +public class ProvidedFromInterfaceWithName implements Provider> { + @Override + public ProvidedInterface get() { + return new Impl(); + } + + private static class Impl implements ProvidedInterface { + + } +} diff --git a/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedInterface.java b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedInterface.java new file mode 100644 index 000000000..db2b22cf2 --- /dev/null +++ b/core/src/test/java/org/seedstack/seed/core/fixtures/ProvidedInterface.java @@ -0,0 +1,12 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.seedstack.seed.core.fixtures; + +public interface ProvidedInterface { +} diff --git a/core/src/test/resources/application.yaml b/core/src/test/resources/application.yaml index 5c8cc41d0..127b1e5fc 100644 --- a/core/src/test/resources/application.yaml +++ b/core/src/test/resources/application.yaml @@ -26,7 +26,7 @@ logging: path: test.log application: id: seed-it - basePackages: some.other.pkg + basePackages: ["some.other.pkg", "${sys.additionalPackage:'dummy'}"] jndi: additionalContexts: test1: jndi-test1.properties diff --git a/pom.xml b/pom.xml index c93807031..aa273370a 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT pom diff --git a/rest/core/pom.xml b/rest/core/pom.xml index 61ddd22a1..78cf4090f 100644 --- a/rest/core/pom.xml +++ b/rest/core/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-rest - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-rest-core diff --git a/rest/jersey2/pom.xml b/rest/jersey2/pom.xml index 876ae74af..7c7f2b844 100644 --- a/rest/jersey2/pom.xml +++ b/rest/jersey2/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-rest - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-rest-jersey2 diff --git a/rest/pom.xml b/rest/pom.xml index 3002b56de..147254312 100644 --- a/rest/pom.xml +++ b/rest/pom.xml @@ -13,7 +13,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-rest diff --git a/rest/specs/pom.xml b/rest/specs/pom.xml index 9f710e5f2..5e69a25a6 100644 --- a/rest/specs/pom.xml +++ b/rest/specs/pom.xml @@ -13,7 +13,7 @@ org.seedstack.seed seed-rest - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-rest-specs diff --git a/security/core/pom.xml b/security/core/pom.xml index e690403ba..56e078e13 100644 --- a/security/core/pom.xml +++ b/security/core/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-security - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-security-core diff --git a/security/pom.xml b/security/pom.xml index dd5ffc1e7..693964ed5 100644 --- a/security/pom.xml +++ b/security/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-security diff --git a/security/specs/pom.xml b/security/specs/pom.xml index 26da88f32..c8914f406 100644 --- a/security/specs/pom.xml +++ b/security/specs/pom.xml @@ -13,7 +13,7 @@ org.seedstack.seed seed-security - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-security-specs diff --git a/specs/pom.xml b/specs/pom.xml index a0beb3911..b9d5177ca 100644 --- a/specs/pom.xml +++ b/specs/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-specs diff --git a/specs/src/main/java/org/seedstack/seed/Bind.java b/specs/src/main/java/org/seedstack/seed/Bind.java index 024ae5c99..4fb60b99f 100644 --- a/specs/src/main/java/org/seedstack/seed/Bind.java +++ b/specs/src/main/java/org/seedstack/seed/Bind.java @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + package org.seedstack.seed; import java.lang.annotation.Documented; @@ -20,10 +21,10 @@ * *

  * {@literal @}Bind
- * public class SomeImplementation {...}
+ *  public class SomeImplementation {...}
  *
  * {@literal @}Inject
- * SomeImplementation someImplementation;
+ *  SomeImplementation someImplementation;
  * 
* *

@@ -33,30 +34,41 @@ * *

  * {@literal @}Bind(from = SomeInterface.class)
- * public class SomeImplementation implements SomeInterface {...}
+ *  public class SomeImplementation implements SomeInterface {...}
  *
  * {@literal @}Inject
- * SomeInterface someInterface;
+ *  SomeInterface someInterface;
  * 
* *

- * When an injection class is specified and a qualifier annotation is present on the implementation class, it is used to - * further refine the injection key: + * The {@link Bind} annotation allows to override any interface-based SeedStack binding. To do this, + * create a custom implementation of the SeedStack interface you want to customize (this is the type you use at the + * injection point) and set the {@link Bind#override()} boolean to true. Your custom implementation will replace the + * SeedStack one. + *

+ *

+ *

+ * When a qualifier annotation is present on the implementation class, it is used to make the injection point more + * specific: *

* *
  * {@literal @}Qualifier
  * {@literal @}Retention(RetentionPolicy.RUNTIME)
- * public interface {@literal @}SomeQualifier {...}
+ *  public interface {@literal @}SomeQualifier {...}
  *
  * {@literal @}Bind(from = SomeInterface.class)
  * {@literal @}SomeQualifier
- * public class SomeImplementation implements SomeInterface {...}
+ *  public class SomeImplementation implements SomeInterface {...}
  *
  * {@literal @}Inject
  * {@literal @}SomeQualifier
- * SomeInterface someInterface;
+ *  SomeInterface someInterface;
  * 
+ * + *

When having multiple implementations of the same interface, using a different qualifier on each implementation + * allows to create multiple bindings. You can then choose the implementation by specifying the corresponding qualifier + * at injection point.

*/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) diff --git a/specs/src/main/java/org/seedstack/seed/Provide.java b/specs/src/main/java/org/seedstack/seed/Provide.java new file mode 100644 index 000000000..6fc379f60 --- /dev/null +++ b/specs/src/main/java/org/seedstack/seed/Provide.java @@ -0,0 +1,82 @@ +/* + * Copyright © 2013-2019, The SeedStack authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.seedstack.seed; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.inject.Provider; + +/** + * This annotation creates an injection binding when applied on a JSR-330 {@link javax.inject.Provider}. It is + * comparable to the {@link Bind} annotation but allow to specify the creation logic of the instance in the + * {@link Provider#get()} method. A provider is itself injectable so you can use any required dependency during the + * creation of the provided instance. + * + *
+ * {@literal @}Provide
+ *  public class Provider{@literal <}SomeClass{@literal >} {
+ *     {@literal @}Inject
+ *      private SomeDependency someDependency;
+ *
+ *      public SomeInterface get() {
+ *          return new SomeClass(someDependency);
+ *      }
+ *  }
+ *
+ * {@literal @}Inject
+ *  SomeClass someClassInstance;
+ * 
+ * + *

+ * The {@link Provide} annotation allows to override any existing SeedStack binding. To do this, + * create a {@link Provider} producing the same type as the SeedStack binding you want to override (this is the type + * you use at the injection point) and set the {@link Provide#override()} boolean to true. The instance produced by your + * provider will replace the SeedStack one. + *

+ *

+ *

+ * When a qualifier annotation is present on the implementation class, it is used to make the injection point more + * specific: + *

+ * + *
+ * {@literal @}Qualifier
+ * {@literal @}Retention(RetentionPolicy.RUNTIME)
+ *  public interface {@literal @}SomeQualifier {...}
+ *
+ * {@literal @}Bind(from = SomeInterface.class)
+ * {@literal @}SomeQualifier
+ *  public class SomeImplementation implements SomeInterface {...}
+ *
+ * {@literal @}Inject
+ * {@literal @}SomeQualifier
+ *  SomeInterface someInterface;
+ * 
+ * + *

When having multiple implementations of the same interface, using a different qualifier on each implementation + * allows to create multiple bindings. You can then choose the implementation by specifying the corresponding qualifier + * at injection point.

+ */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface Provide { + /** + * If true the binding will be defined as an overriding one, meaning that it will override an identical binding + * already defined. If false, the binding will defined as a normal one. + * + * @return if true the binding is an overriding binding, if false a normal binding. + */ + boolean override() default false; +} diff --git a/testing/arquillian/pom.xml b/testing/arquillian/pom.xml index 8e6c2e05d..48ad1e376 100644 --- a/testing/arquillian/pom.xml +++ b/testing/arquillian/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-testing - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-testing-arquillian diff --git a/testing/core/pom.xml b/testing/core/pom.xml index c3d0aefd2..c694dfe96 100644 --- a/testing/core/pom.xml +++ b/testing/core/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-testing - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-testing-core diff --git a/testing/junit4/pom.xml b/testing/junit4/pom.xml index 7eba586f5..f51064afa 100644 --- a/testing/junit4/pom.xml +++ b/testing/junit4/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-testing - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-testing-junit4 diff --git a/testing/pom.xml b/testing/pom.xml index 980911714..113f33b99 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-testing diff --git a/testing/specs/pom.xml b/testing/specs/pom.xml index 01e7229a2..bdfc9a3e0 100644 --- a/testing/specs/pom.xml +++ b/testing/specs/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-testing - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-testing-specs diff --git a/web/core/pom.xml b/web/core/pom.xml index 9caa7e62c..f407d9a1f 100644 --- a/web/core/pom.xml +++ b/web/core/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-web - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-web-core diff --git a/web/pom.xml b/web/pom.xml index a96541a04..a6af6e53a 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-web diff --git a/web/security/pom.xml b/web/security/pom.xml index a50e68546..3dd1e8bee 100644 --- a/web/security/pom.xml +++ b/web/security/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-web - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-web-security diff --git a/web/specs/pom.xml b/web/specs/pom.xml index f81f76f19..7a9bb23c6 100644 --- a/web/specs/pom.xml +++ b/web/specs/pom.xml @@ -13,7 +13,7 @@ org.seedstack.seed seed-web - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-web-specs diff --git a/web/undertow/pom.xml b/web/undertow/pom.xml index 540c45709..79c2fb804 100644 --- a/web/undertow/pom.xml +++ b/web/undertow/pom.xml @@ -14,7 +14,7 @@ org.seedstack.seed seed-web - 3.8.4-SNAPSHOT + 3.8.5-SNAPSHOT seed-web-undertow