Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotation for Named that accepts a class #6779

Merged
merged 1 commit into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
resolves issue #6657
  • Loading branch information
trentjeff committed May 10, 2023
commit 3dd4e3337381a4dd893c6112b3ac2d28abaff6fb
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,27 @@

package io.helidon.pico.api;

import io.helidon.common.types.AnnotationAndValueDefault;
import java.lang.annotation.Documented;
trentjeff marked this conversation as resolved.
Show resolved Hide resolved
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import jakarta.inject.Named;
import org.junit.jupiter.api.Test;
import jakarta.inject.Qualifier;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

class DefaultQualifierAndValueTest {
/**
* This annotation is effectively the same as {@link jakarta.inject.Named} where the {@link Named#value()} is a {@link Class}
* name instead of a {@link String}.
*/
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassNamed {

@Test
void buildAndCompare() {
QualifierAndValueDefault qav1 = QualifierAndValueDefault.builder()
.type(Named.class)
.value("x.y")
.build();
AnnotationAndValueDefault qav2 = QualifierAndValueDefault.builder()
.type(Named.class)
.value("x.y")
.build();
assertThat(qav1.compareTo(qav2),
is(0));
}
/**
* The class used will function as the name.
*
* @return the class
*/
Class<?> value();

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import io.helidon.common.types.TypeName;
import io.helidon.common.types.TypeNameDefault;

import jakarta.inject.Named;

/**
* Describes a {@link jakarta.inject.Qualifier} type annotation associated with a service being provided or dependant upon.
* In Pico these are generally determined at compile time to avoid any use of reflection at runtime.
Expand Down Expand Up @@ -54,6 +56,43 @@ public static QualifierAndValueDefault createNamed(String name) {
return builder().typeName(CommonQualifiers.NAMED).value(name).build();
}

/**
* Creates a {@link jakarta.inject.Named} qualifier.
*
* @param name the name
* @return named qualifier
*/
public static QualifierAndValueDefault createNamed(Named name) {
Objects.requireNonNull(name);
QualifierAndValueDefault.Builder builder = builder().typeName(CommonQualifiers.NAMED);
if (!name.value().isEmpty()) {
builder.value(name.value());
}
return builder.build();
}

/**
* Creates a {@link jakarta.inject.Named} qualifier.
*
* @param name the name
* @return named qualifier
*/
public static QualifierAndValueDefault createNamed(ClassNamed name) {
Objects.requireNonNull(name);
return builder().typeName(CommonQualifiers.NAMED).value(name.value().getName()).build();
}

/**
* Creates a {@link jakarta.inject.Named} qualifier.
*
* @param name the name of the class will be used
* @return named qualifier
*/
public static QualifierAndValueDefault createClassNamed(Class<?> name) {
Objects.requireNonNull(name);
return builder().typeName(CommonQualifiers.NAMED).value(name.getName()).build();
}

/**
* Creates a qualifier from an annotation.
*
Expand All @@ -62,7 +101,8 @@ public static QualifierAndValueDefault createNamed(String name) {
*/
public static QualifierAndValueDefault create(Class<? extends Annotation> qualifierType) {
Objects.requireNonNull(qualifierType);
return builder().typeName(TypeNameDefault.create(qualifierType)).build();
TypeName qualifierTypeName = maybeNamed(qualifierType.getName());
return builder().typeName(qualifierTypeName).build();
}

/**
Expand All @@ -74,7 +114,8 @@ public static QualifierAndValueDefault create(Class<? extends Annotation> qualif
*/
public static QualifierAndValueDefault create(Class<? extends Annotation> qualifierType, String val) {
Objects.requireNonNull(qualifierType);
return builder().typeName(TypeNameDefault.create(qualifierType)).value(val).build();
TypeName qualifierTypeName = maybeNamed(qualifierType.getName());
return builder().typeName(qualifierTypeName).value(val).build();
}

/**
Expand All @@ -85,8 +126,9 @@ public static QualifierAndValueDefault create(Class<? extends Annotation> qualif
* @return qualifier
*/
public static QualifierAndValueDefault create(String qualifierTypeName, String val) {
TypeName qualifierType = maybeNamed(qualifierTypeName);
return builder()
.typeName(TypeNameDefault.createFromTypeName(qualifierTypeName))
.typeName(qualifierType)
.value(val)
.build();
}
Expand All @@ -99,8 +141,9 @@ public static QualifierAndValueDefault create(String qualifierTypeName, String v
* @return qualifier
*/
public static QualifierAndValueDefault create(TypeName qualifierType, String val) {
TypeName qualifierTypeName = maybeNamed(qualifierType);
return builder()
.typeName(qualifierType)
.typeName(qualifierTypeName)
.value(val)
.build();
}
Expand All @@ -113,12 +156,27 @@ public static QualifierAndValueDefault create(TypeName qualifierType, String val
* @return qualifier
*/
public static QualifierAndValueDefault create(TypeName qualifierType, Map<String, String> vals) {
TypeName qualifierTypeName = maybeNamed(qualifierType);
return builder()
.typeName(qualifierType)
.typeName(qualifierTypeName)
.values(vals)
.build();
}

static TypeName maybeNamed(String qualifierTypeName) {
if (qualifierTypeName.equals(ClassNamed.class.getName())) {
return CommonQualifiers.NAMED;
}
return TypeNameDefault.createFromTypeName(qualifierTypeName);
}

static TypeName maybeNamed(TypeName qualifierTypeName) {
if (qualifierTypeName.name().equals(ClassNamed.class.getName())) {
return CommonQualifiers.NAMED;
}
return qualifierTypeName;
}

/**
* Converts from an {@link AnnotationAndValue} to a {@link QualifierAndValue}.
*
Expand All @@ -139,7 +197,7 @@ public static QualifierAndValue convert(AnnotationAndValue annotationAndValue) {
}

return builder()
.typeName(annotationAndValue.typeName())
.typeName(maybeNamed(annotationAndValue.typeName()))
.values(values)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isEmptyOrNullString;

class DefaultPicoConfigTest {
class PicoServicesConfigDefaultTest {

@AfterEach
void reset() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.pico.api;

import java.lang.annotation.Annotation;

import io.helidon.common.types.AnnotationAndValueDefault;

import jakarta.inject.Named;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;

class QualifierAndValueDefaultTest {

@Test
void buildAndCompare() {
QualifierAndValueDefault qav1 = QualifierAndValueDefault.builder()
.type(Named.class)
.value("x.y")
.build();
AnnotationAndValueDefault qav2 = QualifierAndValueDefault.builder()
.type(Named.class)
.value("x.y")
.build();
assertThat(qav1.compareTo(qav2),
is(0));
}

@Test
public void buildAndCompareClassNamed() {
QualifierAndValueDefault qav1 = QualifierAndValueDefault.createNamed(new FakeNamed());
QualifierAndValueDefault qav2 = QualifierAndValueDefault.createNamed(new FakeClassNamed());

assertThat(qav1.compareTo(qav2),
is(0));
assertThat(qav2.compareTo(qav1),
is(0));
}

@Named("io.helidon.pico.api.DefaultQualifierAndValueTest")
@ClassNamed(QualifierAndValueDefaultTest.class)
@Test
public void createClassNamed() throws Exception {
QualifierAndValueDefault qav1 = QualifierAndValueDefault.createClassNamed(QualifierAndValueDefaultTest.class);
QualifierAndValueDefault qav2 = QualifierAndValueDefault.builder()
.type(Named.class)
.value(QualifierAndValueDefault.class.getName())
.build();
assertThat(qav1.compareTo(qav2),
is(0));

assertThat("runtime retention expected for " + ClassNamed.class,
getClass().getMethod("createClassNamed").getAnnotation(ClassNamed.class),
notNullValue());
}

class FakeNamed implements Named {
@Override
public String value() {
return QualifierAndValueDefaultTest.class.getName();
}

@Override
public Class<? extends Annotation> annotationType() {
return Named.class;
}
}

class FakeClassNamed implements ClassNamed {
@Override
public Class value() {
return QualifierAndValueDefaultTest.class;
}

@Override
public Class<? extends Annotation> annotationType() {
return ClassNamed.class;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.pico.tests.pico;

/**
* For Testing.
*/
public class ClassNamedX {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.pico.tests.pico;

/**
* For Testing.
*/
public class ClassNamedY {
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import java.io.IOException;
import java.util.Optional;

import io.helidon.pico.api.ClassNamed;
import io.helidon.pico.api.ExternalContracts;
import io.helidon.pico.tests.pico.ClassNamedX;
import io.helidon.pico.tests.plain.interceptor.IA;
import io.helidon.pico.tests.plain.interceptor.IB;
import io.helidon.pico.tests.plain.interceptor.InterceptorBasedAnno;
Expand All @@ -36,7 +38,7 @@
* Also note that interception was triggered by the presence of the {@link TestNamed} and {@link InterceptorBasedAnno} triggers.
*/
@Singleton
@Named("ClassX")
@ClassNamed(ClassNamedX.class)
@TestNamed("TestNamed-ClassX")
@ExternalContracts(value = Closeable.class, moduleNames = {"test1", "test2"})
@SuppressWarnings("unused")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import java.io.IOException;
import java.util.Optional;

import io.helidon.pico.api.ClassNamed;
import io.helidon.pico.api.ExternalContracts;
import io.helidon.pico.tests.pico.ClassNamedY;
import io.helidon.pico.tests.plain.interceptor.IA;
import io.helidon.pico.tests.plain.interceptor.IB;
import io.helidon.pico.tests.plain.interceptor.InterceptorBasedAnno;
Expand All @@ -36,7 +38,7 @@
* Also note that interception was triggered by the presence of the {@link InterceptorBasedAnno} trigger.
*/
@Singleton
@Named("ClassY")
@ClassNamed(ClassNamedY.class)
@ExternalContracts(value = Closeable.class, moduleNames = {"test1", "test2"})
@SuppressWarnings("unused")
public class YImpl implements IB, Closeable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import io.helidon.pico.api.ServiceProvider;
import io.helidon.pico.api.Services;
import io.helidon.pico.testing.ReflectionBasedSingletonServiceProvider;
import io.helidon.pico.tests.pico.ClassNamedY;
import io.helidon.pico.tests.plain.interceptor.IB;
import io.helidon.pico.tests.plain.interceptor.InterceptorBasedAnno;
import io.helidon.pico.tests.plain.interceptor.TestNamedInterceptor;
Expand Down Expand Up @@ -168,7 +169,7 @@ void runtimeWithNoInterception() throws Exception {
.lookupFirst(
ServiceInfoCriteriaDefault.builder()
.addContractImplemented(Closeable.class.getName())
.qualifiers(Set.of(create(Named.class, "ClassY")))
.qualifiers(Set.of(create(Named.class, ClassNamedY.class.getName())))
.build());
assertThat(toDescription(yimplProvider),
equalTo("YImpl$$Pico$$Interceptor:INIT"));
Expand Down Expand Up @@ -250,7 +251,7 @@ void runtimeWithInterception() throws Exception {
.lookupFirst(
ServiceInfoCriteriaDefault.builder()
.addContractImplemented(Closeable.class.getName())
.qualifiers(Set.of(create(Named.class, "ClassY")))
.qualifiers(Set.of(create(Named.class, ClassNamedY.class.getName())))
.build());
assertThat(toDescription(yimplProvider),
equalTo("YImpl$$Pico$$Interceptor:INIT"));
Expand Down
Loading