From b44b9a4c08979615d2e0702d6d2726b2ce6b42d5 Mon Sep 17 00:00:00 2001 From: Jonathan Coustick Date: Thu, 18 Mar 2021 09:33:24 +0000 Subject: [PATCH 1/3] Injection occurs in correct order for TCK, now all passes --- .../org/jvnet/hk2/internal/ClazzCreator.java | 68 +++++++++++++++++-- .../ClassReflectionHelperUtilities.java | 5 ++ .../internal/MethodWrapperImpl.java | 11 +++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/hk2-locator/src/main/java/org/jvnet/hk2/internal/ClazzCreator.java b/hk2-locator/src/main/java/org/jvnet/hk2/internal/ClazzCreator.java index 6d5b3c55a1..2a2a20fdf3 100755 --- a/hk2-locator/src/main/java/org/jvnet/hk2/internal/ClazzCreator.java +++ b/hk2-locator/src/main/java/org/jvnet/hk2/internal/ClazzCreator.java @@ -50,8 +50,10 @@ public class ClazzCreator implements Creator { private final ServiceLocatorImpl locator; private final Class implClass; - private final Set myInitializers = new LinkedHashSet(); - private final Set myFields = new LinkedHashSet(); + private final Set myInitializers = new LinkedHashSet<>(); + private final Set superInitializers = new LinkedHashSet<>(); + private final Set myFields = new LinkedHashSet<>(); + private final Set superFields = new LinkedHashSet<>(); private ActiveDescriptor selfDescriptor; private ResolutionInfo myConstructor; @@ -127,7 +129,11 @@ public class ClazzCreator implements Creator { baseAllInjectees.addAll(injectees); - myInitializers.add(new ResolutionInfo(element, injectees)); + if (initMethod.getDeclaringClass().equals(implClass)) { + myInitializers.add(new ResolutionInfo(element, injectees)); + } else { + superInitializers.add(new ResolutionInfo(element, injectees)); + } } Set fields = Utilities.getInitFields(implClass, analyzer, collector); @@ -139,7 +145,11 @@ public class ClazzCreator implements Creator { baseAllInjectees.addAll(injectees); - myFields.add(new ResolutionInfo(element, injectees)); + if (field.getDeclaringClass().equals(implClass)) { + myFields.add(new ResolutionInfo(element, injectees)); + } else { + superFields.add(new ResolutionInfo(element, injectees)); + } } postConstructMethod = Utilities.getPostConstruct(implClass, analyzer, collector); @@ -204,6 +214,20 @@ private Map resolveAllDependencies(final ServiceHand InjectionResolver resolver = locator.getInjectionResolverForInjectee(injectee); resolve(retVal, resolver, injectee, root, errorCollector); } + + for (ResolutionInfo fieldRI : superFields) { + for (SystemInjecteeImpl injectee : fieldRI.injectees) { + InjectionResolver resolver = locator.getInjectionResolverForInjectee(injectee); + resolve(retVal, resolver, injectee, root, errorCollector); + } + } + + for (ResolutionInfo methodRI : superInitializers) { + for (SystemInjecteeImpl injectee : methodRI.injectees) { + InjectionResolver resolver = locator.getInjectionResolverForInjectee(injectee); + resolve(retVal, resolver, injectee, root, errorCollector); + } + } for (ResolutionInfo fieldRI : myFields) { for (SystemInjecteeImpl injectee : fieldRI.injectees) { @@ -281,6 +305,22 @@ private void fieldMe(Map resolved, T t) throws Throw ReflectionHelper.setField(field, t, putMeIn); } } + + private void fieldParents(Map resolved, T t) throws Throwable { + for (ResolutionInfo ri : superFields) { + Field field = (Field) ri.baseElement; + List injectees = ri.injectees; // Should be only one injectee, itself! + + Injectee fieldInjectee = null; + for (Injectee candidate : injectees) { + fieldInjectee = candidate; + } + + Object putMeIn = resolved.get(fieldInjectee); + + ReflectionHelper.setField(field, t, putMeIn); + } + } private void methodMe(Map resolved, T t) throws Throwable { for (ResolutionInfo ri : myInitializers) { @@ -295,6 +335,20 @@ private void methodMe(Map resolved, T t) throws Thro ReflectionHelper.invoke(t, m, args, locator.getNeutralContextClassLoader()); } } + + private void methodParents(Map resolved, T t) throws Throwable { + for (ResolutionInfo ri : superInitializers) { + Method m = (Method) ri.baseElement; + List injectees = ri.injectees; + + Object args[] = new Object[injectees.size()]; + for (Injectee injectee : injectees) { + args[injectee.getPosition()] = resolved.get(injectee); + } + + ReflectionHelper.invoke(t, m, args, locator.getNeutralContextClassLoader()); + } + } private void postConstructMe(T t) throws Throwable { if (t == null) return; @@ -340,6 +394,12 @@ public T create(ServiceHandle root, SystemDescriptor eventThrower) { failureLocation = "create"; T retVal = (T) createMe(allResolved); + + failureLocation="parent field inject"; + fieldParents(allResolved, retVal); + + failureLocation = "parent method inject"; + methodParents(allResolved, retVal); failureLocation = "field inject"; fieldMe(allResolved, retVal); diff --git a/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/ClassReflectionHelperUtilities.java b/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/ClassReflectionHelperUtilities.java index 6d1dff730a..5c6572d9a3 100755 --- a/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/ClassReflectionHelperUtilities.java +++ b/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/ClassReflectionHelperUtilities.java @@ -148,6 +148,11 @@ static Set getAllFieldWrappers(Class clazz) { return retVal; } + /** + * Returns methods of a class, including those in superclasses and interfaces. + * @param clazz Class to get methods of + * @return + */ static Set getAllMethodWrappers(Class clazz) { if (clazz == null) return Collections.emptySet(); if (Object.class.equals(clazz)) return OBJECT_METHODS; diff --git a/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/MethodWrapperImpl.java b/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/MethodWrapperImpl.java index 8af361853e..5f6ce02b4e 100755 --- a/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/MethodWrapperImpl.java +++ b/hk2-utils/src/main/java/org/glassfish/hk2/utilities/reflection/internal/MethodWrapperImpl.java @@ -17,6 +17,7 @@ package org.glassfish.hk2.utilities.reflection.internal; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import org.glassfish.hk2.utilities.reflection.MethodWrapper; import org.glassfish.hk2.utilities.reflection.Pretty; @@ -42,12 +43,22 @@ public MethodWrapperImpl(Method method) { hashCode ^= method.getName().hashCode(); hashCode ^= method.getReturnType().hashCode(); + int modifiers = method.getModifiers(); + if (Modifier.isPrivate(modifiers)) { + hashCode ^= method.getDeclaringClass().hashCode(); + } else if (isPackagePrivate(modifiers)) { + hashCode ^= method.getDeclaringClass().getPackage().hashCode(); + } for (Class param : method.getParameterTypes()) { hashCode ^= param.hashCode(); } this.hashCode = hashCode; } + + private boolean isPackagePrivate(int modifiers) { + return !Modifier.isPublic(modifiers) && !Modifier.isProtected(modifiers) && !Modifier.isPrivate(modifiers); + } /* (non-Javadoc) * @see org.glassfish.hk2.utilities.reflection.MethodWrapper#getMethod() From 43c066353c7c6e8cd70c8d27e46a677795fc30fd Mon Sep 17 00:00:00 2001 From: Jonathan Coustick Date: Wed, 24 Mar 2021 09:08:54 +0000 Subject: [PATCH 2/3] Include DI TCK runner and static injection no longer throws an error on processing --- .../org/jvnet/hk2/internal/Utilities.java | 12 +- .../negative/field/NegativeFieldTest.java | 9 +- .../negative/field/StaticFieldService.java | 2 +- .../negative/method/NegativeMethodTest.java | 10 +- hk2-testing/di-tck/pom.xml | 107 ++++++++++++++++++ .../org/glassfish/hk2/ditck/TCKRunner.java | 53 +++++++++ hk2-testing/pom.xml | 2 + 7 files changed, 182 insertions(+), 13 deletions(-) create mode 100644 hk2-testing/di-tck/pom.xml create mode 100644 hk2-testing/di-tck/src/test/java/org/glassfish/hk2/ditck/TCKRunner.java diff --git a/hk2-locator/src/main/java/org/jvnet/hk2/internal/Utilities.java b/hk2-locator/src/main/java/org/jvnet/hk2/internal/Utilities.java index 4c6b1b9b32..30fb4ff1b4 100755 --- a/hk2-locator/src/main/java/org/jvnet/hk2/internal/Utilities.java +++ b/hk2-locator/src/main/java/org/jvnet/hk2/internal/Utilities.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 Payara Services Ltd. + * Copyright (c) 2020, 2021 Payara Services Ltd. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -1419,6 +1419,9 @@ public static Set findInitializerMethods( " is static, abstract or has a parameter that is an annotation")); continue; } + if (Modifier.isStatic(method.getModifiers())) { + continue; + } retVal.add(method); } @@ -1485,6 +1488,9 @@ public static Set findInitializerFields(Class annotatedType, Pretty.field(field) + " may not be static, final or have an Annotation type")); continue; } + if (Modifier.isStatic(field.getModifiers())) { + continue; + } retVal.add(field); } @@ -1518,7 +1524,7 @@ static AnnotatedElementAnnotationInfo computeAEAI(AnnotatedElement annotatedElem } private static boolean isProperMethod(Method member) { - if (ReflectionHelper.isStatic(member)) return false; + //if (ReflectionHelper.isStatic(member)) return false; if (isAbstract(member)) return false; for (Class paramClazz : member.getParameterTypes()) { if (paramClazz.isAnnotation()) { @@ -1530,7 +1536,7 @@ private static boolean isProperMethod(Method member) { } private static boolean isProperField(Field field) { - if (ReflectionHelper.isStatic(field)) return false; + //if (ReflectionHelper.isStatic(field)) return false; if (isFinal(field)) return false; Class type = field.getType(); return !type.isAnnotation(); diff --git a/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/NegativeFieldTest.java b/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/NegativeFieldTest.java index e9251e4f72..05b8582399 100755 --- a/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/NegativeFieldTest.java +++ b/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/NegativeFieldTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Payara Services Ltd. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -36,14 +37,10 @@ public class NegativeFieldTest { */ @Test public void testStaticField() { - try { locator.reifyDescriptor(locator.getBestDescriptor(BuilderHelper.createContractFilter( StaticFieldService.class.getName()))); - Assert.fail("static field should cause failure"); - } - catch (MultiException me) { - Assert.assertTrue(me.getMessage().contains(" may not be static, final or have an Annotation type")); - } + StaticFieldService fieldService = locator.getService(StaticFieldService.class); + Assert.assertNull(fieldService.locator); } /** diff --git a/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/StaticFieldService.java b/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/StaticFieldService.java index 26e6cdf9b6..7edfe12876 100755 --- a/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/StaticFieldService.java +++ b/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/field/StaticFieldService.java @@ -27,6 +27,6 @@ */ public class StaticFieldService { @Inject - static ServiceLocator locator; + public static ServiceLocator locator; } diff --git a/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/method/NegativeMethodTest.java b/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/method/NegativeMethodTest.java index 3ae427fe10..58e0471e01 100755 --- a/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/method/NegativeMethodTest.java +++ b/hk2-locator/src/test/java/org/glassfish/hk2/tests/locator/negative/method/NegativeMethodTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 Payara Services Ltd. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -16,6 +17,7 @@ package org.glassfish.hk2.tests.locator.negative.method; +import org.glassfish.hk2.api.ActiveDescriptor; import org.glassfish.hk2.api.MultiException; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.tests.locator.utilities.LocatorHelper; @@ -37,12 +39,14 @@ public class NegativeMethodTest { @Test public void testStaticMethod() { try { - locator.reifyDescriptor(locator.getBestDescriptor(BuilderHelper.createContractFilter( + ActiveDescriptor descriptor = locator.reifyDescriptor(locator.getBestDescriptor(BuilderHelper.createContractFilter( StaticMethodService.class.getName()))); - Assert.fail("static method should cause failure"); + StaticMethodService methodService = locator.getService(StaticMethodService.class); } catch (MultiException me) { - Assert.assertTrue(me.getMessage().contains("is static, abstract or has a parameter that is an annotation")); + me.printStackTrace(); + Assert.fail(me.getMessage()); + // Assert.assertTrue(me.getMessage(), me.getMessage().contains("is static, abstract or has a parameter that is an annotation")); } } diff --git a/hk2-testing/di-tck/pom.xml b/hk2-testing/di-tck/pom.xml new file mode 100644 index 0000000000..e4dccfe1c6 --- /dev/null +++ b/hk2-testing/di-tck/pom.xml @@ -0,0 +1,107 @@ + + + + + 4.0.0 + + org.glassfish.hk2 + hk2-testing + 3.0.2-SNAPSHOT + + + hk2-di-tck-runner + DI TCK Runner + Runner for the Jakarta DI TCK + + + 2.0.1 + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.1 + + + unpack + process-test-classes + + unpack + + + + + + + jakarta.inject + jakarta.inject-api + 2.0.0 + false + ${project.build.directory}/test-classes + + + jakarta.inject + jakarta.inject-tck + ${ditck.version} + false + ${project.build.directory}/test-classes + + + false + true + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + + + ${runSuite} + + false + + + + + + + + junit + junit + + + jakarta.inject + jakarta.inject-tck + ${ditck.version} + + + org.glassfish.hk2 + hk2-api + ${project.version} + + + org.glassfish.hk2 + hk2-locator + ${project.version} + + + diff --git a/hk2-testing/di-tck/src/test/java/org/glassfish/hk2/ditck/TCKRunner.java b/hk2-testing/di-tck/src/test/java/org/glassfish/hk2/ditck/TCKRunner.java new file mode 100644 index 0000000000..e3cce4b99f --- /dev/null +++ b/hk2-testing/di-tck/src/test/java/org/glassfish/hk2/ditck/TCKRunner.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Payara Services Ltd. and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package org.glassfish.hk2.ditck; + +import jakarta.inject.Singleton; +import org.atinject.tck.Tck; +import org.atinject.tck.auto.*; +import org.atinject.tck.auto.accessories.*; +import org.glassfish.hk2.api.DynamicConfiguration; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.utilities.BuilderHelper; +import org.glassfish.hk2.utilities.ServiceLocatorUtilities; + +/** + * Runner for the DI TCK + * @author Jonathan Coustick + */ +public class TCKRunner { + + public static junit.framework.Test suite() { + + ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator("test-locator"); + DynamicConfiguration dynamicConfig = ServiceLocatorUtilities.createDynamicConfiguration(locator); + + dynamicConfig.bind(BuilderHelper.link(FuelTank.class).build()); + dynamicConfig.bind(BuilderHelper.link(Seat.class).in(Singleton.class).build()); + dynamicConfig.bind(BuilderHelper.link(DriversSeat.class).to(Seat.class).qualifiedBy(Drivers.class.getName()).build()); + dynamicConfig.bind(BuilderHelper.link(Seatbelt.class).build()); + dynamicConfig.bind(BuilderHelper.link(V8Engine.class).to(GasEngine.class).to(Engine.class).build()); + dynamicConfig.bind(BuilderHelper.link(Cupholder.class).in(Singleton.class).build()); + dynamicConfig.bind(BuilderHelper.link(Tire.class).build()); + dynamicConfig.bind(BuilderHelper.link(SpareTire.class).to(Tire.class).named("spare").build()); + dynamicConfig.bind(BuilderHelper.link(Convertible.class).to(Car.class).build()); + + dynamicConfig.commit(); + Car tckCar = locator.getService(Car.class); + return Tck.testsFor(tckCar, false, true); + } + +} diff --git a/hk2-testing/pom.xml b/hk2-testing/pom.xml index 65d6a1ce0c..e8d4970f95 100644 --- a/hk2-testing/pom.xml +++ b/hk2-testing/pom.xml @@ -2,6 +2,7 @@