Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 561B2200C7D for ; Tue, 16 May 2017 20:50:59 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 54D8B160BA6; Tue, 16 May 2017 18:50:59 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id D75A1160BEC for ; Tue, 16 May 2017 20:50:54 +0200 (CEST) Received: (qmail 1850 invoked by uid 500); 16 May 2017 18:50:54 -0000 Mailing-List: contact commits-help@polygene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@polygene.apache.org Delivered-To: mailing list commits@polygene.apache.org Received: (qmail 1537 invoked by uid 99); 16 May 2017 18:50:53 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 16 May 2017 18:50:53 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id DE0CBE9637; Tue, 16 May 2017 18:50:53 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: paulmerlin@apache.org To: commits@polygene.apache.org Date: Tue, 16 May 2017 18:51:24 -0000 Message-Id: In-Reply-To: <68236d0633fc4adcbf189c348ad880b6@git.apache.org> References: <68236d0633fc4adcbf189c348ad880b6@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [32/50] [abbrv] polygene-java git commit: POLYGENE-251 - Fixed Concerns/SideEffects being invoke on default interface methods (JetBrains call them Extension Methods. Is that from JVM Spec?). Still a question mark if Concerns/SideEffects are present in c archived-at: Tue, 16 May 2017 18:50:59 -0000 POLYGENE-251 - Fixed Concerns/SideEffects being invoke on default interface methods (JetBrains call them Extension Methods. Is that from JVM Spec?). Still a question mark if Concerns/SideEffects are present in case they are Generic and not Typed. Signed-off-by: niclas Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/452c7292 Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/452c7292 Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/452c7292 Branch: refs/heads/master Commit: 452c72929631b1aff6f45d13f253b66fcea2bb6a Parents: b028f64 Author: niclas Authored: Mon May 15 19:35:33 2017 +0800 Committer: niclas Committed: Mon May 15 19:35:33 2017 +0800 ---------------------------------------------------------------------- .../bootstrap/CompositeAssemblyImpl.java | 104 +++++++++---------- .../ImplementsMethodAppliesToFilter.java | 4 +- .../runtime/composite/CompositeMethodModel.java | 4 +- .../composite/CompositeMethodsModel.java | 38 +------ .../runtime/composite/ConcernsModel.java | 6 +- .../composite/InterfaceDefaultMethodsMixin.java | 98 +++++++++++++++++ .../polygene/runtime/composite/MixinsModel.java | 7 +- .../runtime/composite/SideEffectsModel.java | 4 +- .../composite/InterfaceDefaultMethodsTest.java | 32 +++--- .../jdbm/JdbmEntityStorePerformanceTest.java | 20 ++-- 10 files changed, 190 insertions(+), 127 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/CompositeAssemblyImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/CompositeAssemblyImpl.java b/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/CompositeAssemblyImpl.java index 14e6300..543e8cd 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/CompositeAssemblyImpl.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/CompositeAssemblyImpl.java @@ -84,6 +84,7 @@ import org.apache.polygene.runtime.composite.ConcernsModel; import org.apache.polygene.runtime.composite.ConstraintModel; import org.apache.polygene.runtime.composite.ConstraintsModel; import org.apache.polygene.runtime.composite.GenericPredicate; +import org.apache.polygene.runtime.composite.InterfaceDefaultMethodsMixin; import org.apache.polygene.runtime.composite.MixinModel; import org.apache.polygene.runtime.composite.MixinsModel; import org.apache.polygene.runtime.composite.SideEffectModel; @@ -97,6 +98,7 @@ import org.apache.polygene.runtime.property.PropertiesModel; import org.apache.polygene.runtime.property.PropertyModel; import static java.util.stream.Stream.concat; +import static java.util.stream.Stream.of; import static org.apache.polygene.api.composite.InvalidCompositeException.handleInvalidCompositeType; import static org.apache.polygene.api.util.Annotations.isType; import static org.apache.polygene.api.util.Annotations.typeHasAnnotation; @@ -113,18 +115,18 @@ import static org.apache.polygene.api.util.Classes.wrapperClass; public abstract class CompositeAssemblyImpl implements HasTypes { - protected List> concerns = new ArrayList<>(); - protected List> sideEffects = new ArrayList<>(); - protected List> mixins = new ArrayList<>(); - protected List> types = new ArrayList<>(); - protected MetaInfo metaInfo = new MetaInfo(); - protected Visibility visibility = Visibility.module; - - protected boolean immutable; - protected PropertiesModel propertiesModel; - protected StateModel stateModel; - protected MixinsModel mixinsModel; - protected CompositeMethodsModel compositeMethodsModel; + List> concerns = new ArrayList<>(); + List> sideEffects = new ArrayList<>(); + List> mixins = new ArrayList<>(); + List> types = new ArrayList<>(); + MetaInfo metaInfo = new MetaInfo(); + Visibility visibility = Visibility.module; + + private boolean immutable; + PropertiesModel propertiesModel; + StateModel stateModel; + MixinsModel mixinsModel; + CompositeMethodsModel compositeMethodsModel; private AssemblyHelper helper; private StateDeclarations stateDeclarations; @@ -192,7 +194,7 @@ public abstract class CompositeAssemblyImpl return stream.collect( Collectors.toList() ); } - protected void addAnnotationsMetaInfo( Class type, MetaInfo compositeMetaInfo ) + private void addAnnotationsMetaInfo( Class type, MetaInfo compositeMetaInfo ) { Class[] declaredInterfaces = type.getInterfaces(); for( int i = declaredInterfaces.length - 1; i >= 0; i-- ) @@ -202,12 +204,12 @@ public abstract class CompositeAssemblyImpl compositeMetaInfo.withAnnotations( type ); } - protected void implementMixinType( List> types, - List> constraintClasses, - List> concernClasses, - List> sideEffectClasses, - List> mixinClasses - ) + private void implementMixinType( List> types, + List> constraintClasses, + List> concernClasses, + List> sideEffectClasses, + List> mixinClasses + ) { List exceptions = new ArrayList<>(); Set> thisDependencies = new HashSet<>(); @@ -294,7 +296,7 @@ public abstract class CompositeAssemblyImpl mixinsModel ); - Stream source = Stream.of( methodComposite, mixinModel ); + Stream source = of( methodComposite, mixinModel ); source.flatMap( Dependencies::dependencies ) .filter( new DependencyModel.ScopeSpecification( This.class ) ) .map( DependencyModel::rawInjectionType ) @@ -302,8 +304,8 @@ public abstract class CompositeAssemblyImpl interfacesOf( mixinModel.mixinClass() ) .map( Classes.RAW_CLASS ) - .filter( clazz -> Stream.of( Initializable.class, Lifecycle.class, InvocationHandler.class ) - .noneMatch( c -> c.equals( clazz ) ) ) + .filter( clazz -> of( Initializable.class, Lifecycle.class, InvocationHandler.class ) + .noneMatch( c -> c.equals( clazz ) ) ) .forEach( thisDependencies::add ); compositeMethodsModel.addMethod( methodComposite ); @@ -317,7 +319,7 @@ public abstract class CompositeAssemblyImpl } @SuppressWarnings( "raw" ) - protected MixinModel implementMethod( Method method, List> mixinDeclarations ) + private MixinModel implementMethod( Method method, List> mixinDeclarations ) { MixinModel implementationModel = mixinsModel.mixinFor( method ); if( implementationModel != null ) @@ -331,15 +333,12 @@ public abstract class CompositeAssemblyImpl } // Check generic implementations - mixinClass = findGenericImplementation( method, mixinDeclarations.stream() ); + mixinClass = findGenericImplementation( method, concat( mixinDeclarations.stream(), of( InterfaceDefaultMethodsMixin.class ) ) ); if( mixinClass != null ) { return implementMethodWithClass( method, mixinClass ); } - if( !method.isDefault() ) // if it is NOT a default method in an interface, we don't have an implementation. - { - handleInvalidCompositeType( "No implementation found for method ", null, null, null, null, method, types ); - } + handleInvalidCompositeType( "No implementation found for method ", null, null, null, null, method, types ); return null; } @@ -369,13 +368,11 @@ public abstract class CompositeAssemblyImpl mixinModel = helper.getMixinModel( mixinClass ); mixinsModel.addMixinModel( mixinModel ); } - mixinsModel.addMethodMixin( method, mixinModel ); - return mixinModel; } - protected void addState( final List> constraintClasses ) + private void addState( final List> constraintClasses ) { // Add method state compositeMethodsModel.accept( new HierarchicalVisitorAdapter() @@ -420,7 +417,7 @@ public abstract class CompositeAssemblyImpl } ); } - protected void addStateFor( AccessibleObject accessor, List> constraintClasses ) + private void addStateFor( AccessibleObject accessor, List> constraintClasses ) { String stateName = QualifiedName.fromAccessor( accessor ).name(); @@ -467,9 +464,9 @@ public abstract class CompositeAssemblyImpl return null; } - protected PropertyModel newPropertyModel( AccessibleObject accessor, - List> constraintClasses - ) + private PropertyModel newPropertyModel( AccessibleObject accessor, + List> constraintClasses + ) { List annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); @@ -519,12 +516,12 @@ public abstract class CompositeAssemblyImpl { Annotation[] parameterAnnotation = parameterAnnotations[ i ]; - Name nameAnnotation = (Name) Stream.of( parameterAnnotation ).filter( isType( Name.class ) ) - .findFirst().orElse( null ); + Name nameAnnotation = (Name) of( parameterAnnotation ).filter( isType( Name.class ) ) + .findFirst().orElse( null ); String name = nameAnnotation == null ? "param" + ( i + 1 ) : nameAnnotation.value(); - boolean optional = Stream.of( parameterAnnotation ) - .anyMatch( isType( Optional.class ) ); + boolean optional = of( parameterAnnotation ) + .anyMatch( isType( Optional.class ) ); ValueConstraintsModel parameterConstraintsModel = constraintsFor( Arrays.stream( parameterAnnotation ), parameterTypes[ i ], @@ -554,14 +551,14 @@ public abstract class CompositeAssemblyImpl } } - protected ValueConstraintsModel constraintsFor( + private ValueConstraintsModel constraintsFor( Stream constraintAnnotations, Type valueType, String name, boolean optional, Iterable> constraintClasses, AccessibleObject accessor - ) + ) { valueType = wrapperClass( valueType ); @@ -578,6 +575,7 @@ public abstract class CompositeAssemblyImpl Class annotationType = constraintAnnotation.annotationType(); for( Class constraint : constraintClasses ) { + @SuppressWarnings( "unchecked" ) Class> constraintType = (Class>) constraint; if( helper.appliesTo( constraintType, annotationType, valueType ) ) { @@ -819,7 +817,7 @@ public abstract class CompositeAssemblyImpl } @SuppressWarnings( "unchecked" ) - protected Stream> sideEffectDeclarations( Class type ) + private Stream> sideEffectDeclarations( Class type ) { Stream types = getTypes( type ); return sideEffectDeclarations( types ); @@ -832,10 +830,10 @@ public abstract class CompositeAssemblyImpl .flatMap( mixinType -> Arrays.stream( Annotations.annotationOn( mixinType, SideEffects.class ).value() ) ); } - protected Stream> mixinDeclarations( Class type ) + private Stream> mixinDeclarations( Class type ) { //Stream types = typesOf( type ); - return mixinDeclarations( Stream.of( type ) ); + return mixinDeclarations( of( type ) ); } private Stream> mixinDeclarations( Stream types ) @@ -862,9 +860,9 @@ public abstract class CompositeAssemblyImpl } } - public AssociationModel newAssociationModel( AccessibleObject accessor, - List> constraintClasses - ) + private AssociationModel newAssociationModel( AccessibleObject accessor, + List> constraintClasses + ) { List annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); @@ -898,9 +896,9 @@ public abstract class CompositeAssemblyImpl return new AssociationModel( accessor, valueConstraintsInstance, associationValueConstraintsInstance, metaInfo ); } - public ManyAssociationModel newManyAssociationModel( AccessibleObject accessor, - List> constraintClasses - ) + private ManyAssociationModel newManyAssociationModel( AccessibleObject accessor, + List> constraintClasses + ) { List annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); @@ -925,9 +923,9 @@ public abstract class CompositeAssemblyImpl return new ManyAssociationModel( accessor, valueConstraintsInstance, manyValueConstraintsInstance, metaInfo ); } - public NamedAssociationModel newNamedAssociationModel( AccessibleObject accessor, - List> constraintClasses - ) + private NamedAssociationModel newNamedAssociationModel( AccessibleObject accessor, + List> constraintClasses + ) { List annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ImplementsMethodAppliesToFilter.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ImplementsMethodAppliesToFilter.java b/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ImplementsMethodAppliesToFilter.java index fd5b04c..a188253 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ImplementsMethodAppliesToFilter.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ImplementsMethodAppliesToFilter.java @@ -35,8 +35,8 @@ final class ImplementsMethodAppliesToFilter { try { - return !Modifier.isAbstract( fragmentClass.getMethod( method.getName(), method.getParameterTypes() ) - .getModifiers() ); + Method fragmentMethod = fragmentClass.getMethod( method.getName(), method.getParameterTypes() ); + return !Modifier.isAbstract( fragmentMethod.getModifiers() ); } catch( NoSuchMethodException e ) { http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java index e0e9b98..d290f97 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java @@ -93,7 +93,9 @@ public final class CompositeMethodModel @SuppressWarnings( "unchecked" ) public Stream dependencies() { - return Stream.of( concerns, sideEffects ).filter( Objects::nonNull ).flatMap( Dependencies::dependencies ); + Stream concerns = Stream.of( this.concerns, sideEffects ); + Stream filteredNonNull = concerns.filter( Objects::nonNull ); + return filteredNonNull.flatMap( Dependencies::dependencies ); } // Context http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java index 25b98f7..2223091 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java @@ -19,16 +19,10 @@ */ package org.apache.polygene.runtime.composite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.polygene.api.composite.Composite; @@ -45,7 +39,6 @@ import org.apache.polygene.runtime.injection.DependencyModel; public final class CompositeMethodsModel implements VisitableHierarchy, Dependencies { - private final ConcurrentMap methodHandleCache = new ConcurrentHashMap<>(); private final LinkedHashMap methods; private final MixinsModel mixinsModel; @@ -103,8 +96,7 @@ public final class CompositeMethodsModel { if( proxy instanceof Composite ) { - MethodCallHandler callHandler = forMethod( method ); - return callHandler.invoke( proxy, args ); + throw new InternalError( "This shouldn't happen!" ); } // Does this next line actually make any sense? Can we have a default method on an interface where the instance is not a Composite? Maybe... Let's try to trap a usecase by disallowing it. // return method.invoke( proxy, args ); @@ -166,32 +158,4 @@ public final class CompositeMethodsModel return methods().toString(); } - private MethodCallHandler forMethod( Method method ) - { - return methodHandleCache.computeIfAbsent( method, this::createMethodCallHandler ); - } - - private MethodCallHandler createMethodCallHandler( Method method ) - { - Class declaringClass = method.getDeclaringClass(); - try - { - Constructor constructor = MethodHandles.Lookup.class.getDeclaredConstructor( Class.class, int.class ); - constructor.setAccessible( true ); - MethodHandles.Lookup lookup = constructor.newInstance( declaringClass, MethodHandles.Lookup.PRIVATE ); - MethodHandle handle = lookup.unreflectSpecial( method, declaringClass ); - return ( proxy, args ) -> handle.bindTo( proxy ).invokeWithArguments( args ); - } - catch( IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException e ) - { - throw new RuntimeException( e ); - } - } - - @FunctionalInterface - private interface MethodCallHandler - { - Object invoke( Object proxy, Object[] args ) - throws Throwable; - } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java index 9c16505..5dde8ce 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java @@ -17,7 +17,6 @@ * * */ - package org.apache.polygene.runtime.composite; import java.lang.reflect.InvocationHandler; @@ -55,18 +54,15 @@ public final class ConcernsModel // Context public ConcernsInstance newInstance( Method method, ModuleDescriptor module, - FragmentInvocationHandler mixinInvocationHandler - ) + FragmentInvocationHandler mixinInvocationHandler ) { ProxyReferenceInvocationHandler proxyHandler = new ProxyReferenceInvocationHandler(); InvocationHandler nextConcern = mixinInvocationHandler; for( int i = concernsFor.size() - 1; i >= 0; i-- ) { ConcernModel concernModel = concernsFor.get( i ); - nextConcern = concernModel.newInstance( module, nextConcern, proxyHandler, method ); } - return new ConcernsInstance( nextConcern, mixinInvocationHandler, proxyHandler ); } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsMixin.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsMixin.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsMixin.java new file mode 100644 index 0000000..b150a86 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsMixin.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.polygene.runtime.composite; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.polygene.api.common.AppliesTo; +import org.apache.polygene.api.common.AppliesToFilter; +import org.apache.polygene.api.composite.Composite; +import org.apache.polygene.api.injection.scope.This; + +@AppliesTo( { InterfaceDefaultMethodsMixin.DefaultMethodsFilter.class } ) +public class InterfaceDefaultMethodsMixin + implements InvocationHandler +{ + // TODO (niclas): We have one instance of this class per mixin, so it seems a bit wasteful to have a ConcurrentHashMap. Maybe a small array 3 elements, which is changed to a Map is run out of space? Tricky concurrency on that, so leave it for later (a.k.a. will forget about it) + private final ConcurrentMap methodHandleCache = new ConcurrentHashMap<>(); + + @This + private Composite me; + + @Override + public Object invoke( Object proxy, Method method, Object[] args ) + throws Throwable + { + if( method.isDefault() ) + { + // Call the interface's default method + MethodCallHandler callHandler = forMethod( method ); + return callHandler.invoke( proxy, args ); + } + // call the composite's method instead. + return method.invoke( me, args ); + } + + /** + * Filter Default Interface Methods to apply generic Mixin. + */ + public static class DefaultMethodsFilter + implements AppliesToFilter + { + @Override + public boolean appliesTo( Method method, Class mixin, Class compositeType, Class modifierClass ) + { + return method.isDefault(); + } + } + + private MethodCallHandler forMethod( Method method ) + { + return methodHandleCache.computeIfAbsent( method, this::createMethodCallHandler ); + } + + private MethodCallHandler createMethodCallHandler( Method method ) + { + Class declaringClass = method.getDeclaringClass(); + try + { + Constructor constructor = MethodHandles.Lookup.class.getDeclaredConstructor( Class.class, int.class ); + constructor.setAccessible( true ); + MethodHandles.Lookup lookup = constructor.newInstance( declaringClass, MethodHandles.Lookup.PRIVATE ); + MethodHandle handle = lookup.unreflectSpecial( method, declaringClass ); + return ( proxy, args ) -> handle.bindTo( proxy ).invokeWithArguments( args ); + } + catch( IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException e ) + { + throw new RuntimeException( e ); + } + } + + @FunctionalInterface + private interface MethodCallHandler + { + Object invoke( Object proxy, Object[] args ) + throws Throwable; + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/composite/MixinsModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/MixinsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/MixinsModel.java index 8a3390d..35efb9d 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/MixinsModel.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/MixinsModel.java @@ -189,7 +189,12 @@ public class MixinsModel public FragmentInvocationHandler newInvocationHandler( final Method method ) { - return mixinFor( method ).newInvocationHandler( method ); + MixinModel mixinModel = mixinFor( method ); + if( mixinModel == null ) + { + throw new InternalError( "MixinModel can't be found." ); + } + return mixinModel.newInvocationHandler( method ); } public Stream dependencies() http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SideEffectsModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SideEffectsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SideEffectsModel.java index b56b363..576b188 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SideEffectsModel.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SideEffectsModel.java @@ -17,7 +17,6 @@ * * */ - package org.apache.polygene.runtime.composite; import java.lang.reflect.InvocationHandler; @@ -55,7 +54,8 @@ public final class SideEffectsModel } // Context - public SideEffectsInstance newInstance( Method method, ModuleDescriptor module, InvocationHandler invoker ) + public SideEffectsInstance newInstance( Method method, ModuleDescriptor module, + InvocationHandler invoker ) { ProxyReferenceInvocationHandler proxyHandler = new ProxyReferenceInvocationHandler(); SideEffectInvocationHandlerResult result = new SideEffectInvocationHandlerResult(); http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/core/runtime/src/test/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsTest.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/test/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsTest.java b/core/runtime/src/test/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsTest.java index 76dde88..5a57a82 100644 --- a/core/runtime/src/test/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsTest.java +++ b/core/runtime/src/test/java/org/apache/polygene/runtime/composite/InterfaceDefaultMethodsTest.java @@ -28,12 +28,10 @@ import org.apache.polygene.bootstrap.AssemblyException; import org.apache.polygene.bootstrap.ModuleAssembly; import org.apache.polygene.library.constraints.annotation.NotEmpty; import org.apache.polygene.test.AbstractPolygeneTest; -import org.junit.Ignore; import org.junit.Test; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; /** @@ -79,18 +77,23 @@ public class InterfaceDefaultMethodsTest extends AbstractPolygeneTest } } + @Concerns( DefaultMethodsConcern.class ) public interface DefaultMethodsConcerns extends DefaultMethods { - @Concerns( DefaultMethodsConcern.class ) @Override default String sayHello( String name ) { return greeting().get() + ", " + name + '!'; } + + default String sayGoodBye( String name ) + { + return "Good Bye, " + name + '!'; + } } - public static abstract class DefaultMethodsConcern extends ConcernOf - implements DefaultMethods + public static abstract class DefaultMethodsConcern extends ConcernOf + implements DefaultMethodsConcerns { @Override public String sayHello( String name ) @@ -99,9 +102,9 @@ public class InterfaceDefaultMethodsTest extends AbstractPolygeneTest } } + @SideEffects( DefaultMethodsSideEffect.class ) public interface DefaultMethodsSideEffects extends DefaultMethods { - @SideEffects( DefaultMethodsSideEffect.class ) @Override default String sayHello( String name ) { @@ -112,25 +115,27 @@ public class InterfaceDefaultMethodsTest extends AbstractPolygeneTest public static abstract class DefaultMethodsSideEffect extends SideEffectOf implements DefaultMethodsSideEffects { - static boolean invoked = false; + static int count; @Override public String sayHello( String name ) { - invoked = true; + count++; return null; } } @Override - public void assemble( final ModuleAssembly module ) throws AssemblyException + public void assemble( final ModuleAssembly module ) + throws AssemblyException { module.transients( DefaultMethods.class, OverrideDefaultMethods.class, MixinDefaultMethods.class, DefaultMethodsConstraints.class, DefaultMethodsConcerns.class, - DefaultMethodsSideEffects.class ); + DefaultMethodsSideEffects.class + ); } @Test @@ -168,20 +173,21 @@ public class InterfaceDefaultMethodsTest extends AbstractPolygeneTest } } - @Ignore( "POLYGENE-120" ) @Test public void defaultMethodsConcerns() { DefaultMethodsConcerns composite = transientBuilderFactory.newTransient( DefaultMethodsConcerns.class ); assertThat( composite.sayHello( "John" ), equalTo( "Hello, concerned John!" ) ); + assertThat( composite.sayGoodBye( "John" ), equalTo( "Good Bye, John!" ) ); } - @Ignore( "POLYGENE-120" ) @Test public void defaultMethodsSideEffects() { DefaultMethodsSideEffects composite = transientBuilderFactory.newTransient( DefaultMethodsSideEffects.class ); assertThat( composite.sayHello( "John" ), equalTo( "Hello, John!" ) ); - assertThat( DefaultMethodsSideEffect.invoked, is( true ) ); + assertThat( composite.sayHello( "John" ), equalTo( "Hello, John!" ) ); + assertThat( composite.sayHello( "John" ), equalTo( "Hello, John!" ) ); + assertThat( DefaultMethodsSideEffect.count, equalTo( 3 ) ); } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/452c7292/tests/performance/src/perf/java/org/apache/polygene/test/performance/entitystore/jdbm/JdbmEntityStorePerformanceTest.java ---------------------------------------------------------------------- diff --git a/tests/performance/src/perf/java/org/apache/polygene/test/performance/entitystore/jdbm/JdbmEntityStorePerformanceTest.java b/tests/performance/src/perf/java/org/apache/polygene/test/performance/entitystore/jdbm/JdbmEntityStorePerformanceTest.java index 006cf85..3b4e179 100644 --- a/tests/performance/src/perf/java/org/apache/polygene/test/performance/entitystore/jdbm/JdbmEntityStorePerformanceTest.java +++ b/tests/performance/src/perf/java/org/apache/polygene/test/performance/entitystore/jdbm/JdbmEntityStorePerformanceTest.java @@ -21,7 +21,6 @@ import java.io.File; import org.apache.derby.iapi.services.io.FileUtil; import org.apache.polygene.api.common.Visibility; import org.apache.polygene.bootstrap.Assembler; -import org.apache.polygene.bootstrap.AssemblyException; import org.apache.polygene.bootstrap.ModuleAssembly; import org.apache.polygene.cache.ehcache.EhCacheConfiguration; import org.apache.polygene.cache.ehcache.EhCachePoolService; @@ -43,20 +42,15 @@ public class JdbmEntityStorePerformanceTest private static Assembler createAssembler() { - return new Assembler() + return module -> { - @Override - public void assemble( ModuleAssembly module ) - throws AssemblyException - { - new JdbmEntityStoreAssembler().assemble( module ); - ModuleAssembly configModule = module.layer().module( "Config" ); - configModule.entities( JdbmConfiguration.class ).visibleIn( Visibility.layer ); - new EntityTestAssembler().assemble( configModule ); + new JdbmEntityStoreAssembler().assemble( module ); + ModuleAssembly configModule = module.layer().module( "Config" ); + configModule.entities( JdbmConfiguration.class ).visibleIn( Visibility.layer ); + new EntityTestAssembler().assemble( configModule ); - module.services( EhCachePoolService.class ); - configModule.entities( EhCacheConfiguration.class ).visibleIn( Visibility.layer ); - } + module.services( EhCachePoolService.class ); + configModule.entities( EhCacheConfiguration.class ).visibleIn( Visibility.layer ); }; }