You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2019/10/04 20:03:50 UTC
[isis] branch v2 updated: ISIS-2158: annotation scanning: minor
performance tweaks
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/v2 by this push:
new e88bb5a ISIS-2158: annotation scanning: minor performance tweaks
e88bb5a is described below
commit e88bb5a8fe31db0059e51c65a2aee75a87137f3e
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Oct 4 22:03:41 2019 +0200
ISIS-2158: annotation scanning: minor performance tweaks
- also adding caches, but these are all disabled for now
- we'll need a large sample domain to actually measure performance
---
.../commons/internal/reflection/_Annotations.java | 52 ++-
.../internal/reflection/_AnnotationsLegacy.java | 361 +++++++++++++++++++++
.../reflection/_Annotations_SyntCache.java | 78 +++++
.../isis/metamodel/facets/DomainEventHelper.java | 9 +-
.../apache/isis/metamodel/facets/FacetFactory.java | 10 +-
.../metamodel/facets/jaxb/JaxbFacetFactory.java | 4 +-
.../DisableForSessionFacetViaMethod.java | 2 +-
.../forsession/HideForSessionFacetViaMethod.java | 2 +-
.../method/ActionChoicesFacetViaMethod.java | 8 +-
.../method/ActionChoicesFacetViaMethodFactory.java | 3 +-
.../ActionParameterDefaultsFacetViaMethod.java | 2 +-
...tionParameterDefaultsFacetViaMethodFactory.java | 4 +-
.../domainmodel/SpecloaderPerformanceTest.java | 20 +-
13 files changed, 509 insertions(+), 46 deletions(-)
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Annotations.java b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Annotations.java
index 403e496..99bf6ac 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Annotations.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Annotations.java
@@ -62,6 +62,13 @@ public final class _Annotations {
return synthesize(annotatedElement, annotationType);
}
+ //final static _Probe probe1 = _Probe.unlimited().label("synthesizeInherited");
+ //final static _Probe probe2 = _Probe.unlimited().label("synthesizeInherited");
+ private final static _Annotations_SyntCache syntCache = new _Annotations_SyntCache();
+ public static void clearCache() {
+ syntCache.clear();
+ }
+
/**
* Optionally create a type-safe synthesized version of this annotation based on presence.
* <p>
@@ -77,6 +84,25 @@ public final class _Annotations {
AnnotatedElement annotatedElement,
Class<A> annotationType) {
+ //probe1.println("lookup");
+
+ //return _AnnotationsLegacy.nearest(annotatedElement, annotationType);
+
+ return calc_synthesizeInherited(annotatedElement, annotationType);
+
+
+// return syntCache.computeIfAbsent(
+// annotatedElement,
+// annotationType,
+// _Annotations::calc_synthesizeInherited);
+ }
+
+ private static <A extends Annotation> Optional<A> calc_synthesizeInherited(
+ AnnotatedElement annotatedElement,
+ Class<A> annotationType) {
+
+ //probe2.println("cache-miss");
+
val collected = _Annotations
.collect(annotatedElement);
@@ -111,7 +137,7 @@ public final class _Annotations {
* @return non-null
*/
public static <A extends Annotation> Optional<A> synthesize(
- Class<?> annotatedElement,
+ AnnotatedElement annotatedElement,
Class<A> annotationType) {
val synthesized = _Annotations
@@ -128,10 +154,13 @@ public final class _Annotations {
/**
* @apiNote don't expose Spring's MergedAnnotations
*/
- private static MergedAnnotations collect(AnnotatedElement annotatedElement) {
+ static MergedAnnotations collect(AnnotatedElement annotatedElement) {
- //TODO use cache if not already
val collected = MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS);
+
+// val collected = syntCache.computeIfAbsent(annotatedElement, __->
+// MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS));
+
return collected;
}
@@ -139,23 +168,12 @@ public final class _Annotations {
if(ReflectionUtils.isObjectMethod(getter)) {
return null;
}
- val fieldNameCandidate1 = fieldNameForGetter(getter);
- if(fieldNameCandidate1==null) {
+ val fieldNameCandidate = fieldNameForGetter(getter);
+ if(fieldNameCandidate==null) {
return null;
}
- //val fieldNameCandidate2 = "_" + fieldNameCandidate1; //XXX legacy behavior
-
val declaringClass = getter.getDeclaringClass();
- for(val field : declaringClass.getDeclaredFields()) { //TODO use cache if appropriate ... ReflectionUtils.findField(clazz, name)
- val fieldName = field.getName();
- if(fieldName.equals(fieldNameCandidate1)) {
- return field;
- }
-// if(fieldName.equals(fieldNameCandidate2)) { //XXX legacy behavior
-// return field;
-// }
- }
- return null;
+ return ReflectionUtils.findField(declaringClass, fieldNameCandidate);
}
private static String fieldNameForGetter(Method getter) {
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_AnnotationsLegacy.java b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_AnnotationsLegacy.java
new file mode 100644
index 0000000..df88b6e
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_AnnotationsLegacy.java
@@ -0,0 +1,361 @@
+/*
+ * 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.isis.commons.internal.reflection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.apache.isis.commons.internal.base._Casts;
+import org.apache.isis.commons.internal.collections._Lists;
+
+import static org.apache.isis.commons.internal.base._NullSafe.stream;
+
+import lombok.val;
+
+public final class _AnnotationsLegacy {
+
+ private _AnnotationsLegacy() {}
+
+ public static <A extends Annotation> Optional<A> nearest(
+ AnnotatedElement annotatedElement,
+ Class<A> annotationType) {
+
+ if(annotatedElement instanceof Method) {
+ return _AnnotationsLegacy.getAnnotations((Method)annotatedElement, annotationType)
+ .stream()
+ .findFirst();
+ }
+ if(annotatedElement instanceof Parameter) {
+ val param = (Parameter)annotatedElement;
+ val method = (Method)param.getDeclaringExecutable();
+ val params = method.getParameters();
+ for(int i = 0 ; i<params.length; ++i) {
+ int paramIndex = i;
+ if(params[i] == param) {
+ return _AnnotationsLegacy.getAnnotations(method, paramIndex, annotationType)
+ .stream()
+ .findFirst();
+ }
+ }
+ throw new NoSuchElementException();
+
+
+ }
+ return _AnnotationsLegacy.getAnnotations((Class<?>)annotatedElement, annotationType)
+ .stream()
+ .findFirst();
+
+ }
+
+ private static class AnnotationAndDepth<T extends Annotation>
+ implements Comparable<AnnotationAndDepth<T>> {
+ AnnotationAndDepth(final T annotation, final int depth) {
+ this.annotation = annotation;
+ this.depth = depth;
+ }
+ T annotation;
+
+ private static <T extends Annotation> List<T> sorted(
+ final List<AnnotationAndDepth<T>> annotationAndDepths) {
+ Collections.sort(annotationAndDepths);
+ return annotationAndDepths.stream()
+ .map(AnnotationAndDepth::getAnnotation)
+ .collect(Collectors.toList());
+ }
+
+ T getAnnotation() {
+ return annotation;
+ }
+ int depth;
+
+ @Override
+ public int compareTo(final AnnotationAndDepth<T> o) {
+ return depth - o.depth;
+ }
+ }
+
+
+ /**
+ * Searches for annotation on provided class, and if not found for the
+ * superclass.
+ * @deprecated use {@link _Annotations} instead
+ */
+ public static <T extends Annotation> List<T> getAnnotations(
+ final Class<?> cls,
+ final Class<T> annotationClass) {
+
+ if (cls == null) {
+ return Collections.emptyList();
+ }
+
+ final List<AnnotationAndDepth<T>> annotationAndDepths = _Lists.newArrayList();
+ for (final Annotation annotation : cls.getAnnotations()) {
+ append(annotation, annotationClass, annotationAndDepths);
+ }
+ if(!annotationAndDepths.isEmpty()) {
+ return AnnotationAndDepth.sorted(annotationAndDepths);
+ }
+
+ // search superclasses
+ final Class<?> superclass = cls.getSuperclass();
+ if (superclass != null) {
+ try {
+ final List<T> annotationsFromSuperclass = getAnnotations(superclass, annotationClass);
+ if (!annotationsFromSuperclass.isEmpty()) {
+ return annotationsFromSuperclass;
+ }
+ } catch (final SecurityException e) {
+ // fall through
+ }
+ }
+
+ // search implemented interfaces
+ final Class<?>[] interfaces = cls.getInterfaces();
+ for (final Class<?> iface : interfaces) {
+ final List<T> annotationsFromInterface = getAnnotations(iface, annotationClass);
+ if (!annotationsFromInterface.isEmpty()) {
+ return annotationsFromInterface;
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private static <T extends Annotation> void append(
+ final Annotation annotation,
+ final Class<T> annotationClass,
+ final List<AnnotationAndDepth<T>> annotationAndDepths) {
+
+ appendWithDepth(annotation, annotationClass, annotationAndDepths, 0, _Lists.newArrayList());
+ }
+
+ private static <T extends Annotation> void appendWithDepth(
+ final Annotation annotation,
+ final Class<T> annotationClass,
+ final List<AnnotationAndDepth<T>> annotationAndDepths,
+ final int depth,
+ final List<Annotation> visited) {
+ if (visited.contains(annotation)) {
+ return;
+ } else {
+ // prevent infinite loop
+ visited.add(annotation);
+ }
+ final Class<? extends Annotation> annotationType = annotation.annotationType();
+
+ // directly annotated
+ if(annotationClass.isAssignableFrom(annotationType)) {
+ annotationAndDepths.add(new AnnotationAndDepth<>(_Casts.uncheckedCast(annotation), depth));
+ }
+
+ // if meta-annotation
+ //if(annotationType.getAnnotation(Meta.class) != null) {
+ final Annotation[] annotationsOnAnnotation = annotationType.getAnnotations();
+ for (final Annotation annotationOnAnnotation : annotationsOnAnnotation) {
+ appendWithDepth(annotationOnAnnotation, annotationClass, annotationAndDepths, depth+1, visited);
+ }
+ //}
+ }
+
+ /**
+ * Searches for annotation on provided method, and if not found for any
+ * inherited methods up from the superclass.
+ * @deprecated use {@link _Annotations} instead
+ */
+ public static <T extends Annotation> List<T> getAnnotations(
+ final Method method,
+ final Class<T> annotationClass) {
+ if (method == null) {
+ return Collections.emptyList();
+ }
+
+ final List<AnnotationAndDepth<T>> annotationAndDepths = _Lists.newArrayList();
+ for (final Annotation annotation : method.getAnnotations()) {
+ append(annotation, annotationClass, annotationAndDepths);
+ }
+ if(!annotationAndDepths.isEmpty()) {
+ return AnnotationAndDepth.sorted(annotationAndDepths);
+ }
+
+
+ // search for field
+ if ( shouldSearchForField(annotationClass) ) {
+ declaredFields_matching(method.getDeclaringClass(), isFieldForGetter(method), field->{
+ for(final Annotation annotation: field.getAnnotations()) {
+ append(annotation, annotationClass, annotationAndDepths);
+ }
+ });
+ }
+ if(!annotationAndDepths.isEmpty()) {
+ return AnnotationAndDepth.sorted(annotationAndDepths);
+ }
+
+ // search superclasses
+ final Class<?> superclass = method.getDeclaringClass().getSuperclass();
+ if (superclass != null) {
+ final Method parentClassMethod =
+ firstDeclaredMethod_matching(method, superclass, isSuperMethodFor(method));
+
+ if(parentClassMethod!=null) {
+ final List<T> annotationsFromSuperclass =
+ getAnnotations(parentClassMethod, annotationClass);
+ if(!annotationsFromSuperclass.isEmpty()) {
+ return annotationsFromSuperclass;
+ }
+ }
+ }
+
+ // search implemented interfaces
+ final Class<?>[] interfaces = method.getDeclaringClass().getInterfaces();
+ for (final Class<?> iface : interfaces) {
+ final Method ifaceMethod =
+ firstDeclaredMethod_matching(method, iface, isSuperMethodFor(method));
+
+ if(ifaceMethod!=null) {
+ final List<T> annotationsFromInterfaces = getAnnotations(ifaceMethod, annotationClass);
+ if(!annotationsFromInterfaces.isEmpty()) {
+ return annotationsFromInterfaces;
+ }
+ }
+ }
+
+ return Collections.emptyList();
+ }
+
+
+//XXX optimization
+// private static List<Class<?>> fieldAnnotationClasses =
+// _Lists.of(
+// Property.class,
+// PropertyLayout.class,
+// Collection.class,
+// CollectionLayout.class,
+// Programmatic.class,
+// MemberOrder.class,
+// Pattern.class,
+// javax.annotation.Nullable.class,
+// Title.class,
+// XmlJavaTypeAdapter.class,
+// XmlTransient.class,
+// javax.jdo.annotations.Column.class
+// );
+
+ private static boolean shouldSearchForField(final Class<?> annotationClass) {
+ return true; //fieldAnnotationClasses.contains(annotationClass);
+ }
+
+ /**
+ * Searches for parameter annotations on provided method, and if not found
+ * for any inherited methods up from the superclass.
+ *
+ * <p>
+ * Added to allow bytecode-mangling libraries such as CGLIB to be supported.
+ * @deprecated use {@link _Annotations} instead
+ */
+ private static <T extends Annotation> List<T> getAnnotations(
+ final Method method,
+ final int paramNum,
+ final Class<T> annotationClass) {
+
+ if(method == null || paramNum < 0 || paramNum >= method.getParameterCount()) {
+ return Collections.emptyList();
+ }
+
+ final List<AnnotationAndDepth<T>> annotationAndDepths = _Lists.newArrayList();
+ final Annotation[] parameterAnnotations = method.getParameterAnnotations()[paramNum];
+ for (Annotation annotation : parameterAnnotations) {
+ append(annotation, annotationClass, annotationAndDepths);
+ }
+ if(!annotationAndDepths.isEmpty()) {
+ return AnnotationAndDepth.sorted(annotationAndDepths);
+ }
+
+ return Collections.emptyList();
+ }
+
+ // -- HELPER
+
+ private static Method firstDeclaredMethod_matching(
+ Method method,
+ Class<?> type,
+ Predicate<Method> filter) {
+
+ return stream(type.getDeclaredMethods())
+ .filter(filter)
+ .findFirst()
+ .orElse(null);
+ }
+
+
+ private static void declaredFields_matching(
+ Class<?> type,
+ Predicate<Field> filter,
+ Consumer<Field> onField) {
+
+ stream(type.getDeclaredFields())
+ .filter(filter)
+ .forEach(onField);
+
+ }
+
+ // -- HELPER - PREDICATES
+
+ private static Predicate<Method> isSuperMethodFor(final Method method) {
+ return m->_Reflect.same(method, m);
+ }
+
+ private static Predicate<Field> isFieldForGetter(final Method getter) {
+ return field->{
+ int beginIndex;
+ final String methodName = getter.getName();
+ if (methodName.startsWith("get")) {
+ beginIndex = 3;
+ } else if (methodName.startsWith("is")) {
+ beginIndex = 2;
+ } else {
+ return false;
+ }
+ if(methodName.length()==beginIndex) {
+ return false;
+ }
+ final String suffix = methodName.substring(beginIndex);
+ final char c = suffix.charAt(0);
+ final char lower = Character.toLowerCase(c);
+ final String candidate = "" + lower + suffix.substring(1);
+ if(field.getName().equals(candidate)) {
+ return true;
+ }
+ if(field.getName().equals("_" + candidate)) {
+ return true;
+ }
+ return false;
+ };
+ }
+
+}
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Annotations_SyntCache.java b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Annotations_SyntCache.java
new file mode 100644
index 0000000..f208630
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Annotations_SyntCache.java
@@ -0,0 +1,78 @@
+/*
+ * 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.isis.commons.internal.reflection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import org.springframework.core.annotation.MergedAnnotations;
+
+import org.apache.isis.commons.internal.collections._Maps;
+
+import lombok.Value;
+import lombok.val;
+
+final class _Annotations_SyntCache {
+
+ // -- L2 CACHE
+
+ @Value(staticConstructor = "of")
+ private final static class Key {
+ AnnotatedElement annotatedElement;
+ Class<? extends Annotation> annotationType;
+ }
+
+ private Map<Key, Optional<?>> map = _Maps.newConcurrentHashMap();
+
+ @SuppressWarnings("unchecked")
+ <A extends Annotation> Optional<A> computeIfAbsent(
+ AnnotatedElement annotatedElement,
+ Class<A> annotationType,
+ BiFunction<AnnotatedElement, Class<A>, Optional<A>> factory) {
+
+ val key = Key.of(annotatedElement, annotationType);
+
+ return (Optional<A>) map.computeIfAbsent(key, __->factory.apply(annotatedElement, annotationType));
+ }
+
+ // -- L1 CACHE
+
+ private Map<AnnotatedElement, MergedAnnotations> mergedByTarget = _Maps.newConcurrentHashMap();
+
+ MergedAnnotations computeIfAbsent(
+ AnnotatedElement annotatedElement,
+ Function<AnnotatedElement, MergedAnnotations> factory) {
+
+ val key = annotatedElement;
+ return mergedByTarget.computeIfAbsent(key, factory);
+ }
+
+ // -- CLEANUP
+
+ void clear() {
+ map.clear();
+ mergedByTarget.clear();
+ }
+
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/DomainEventHelper.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/DomainEventHelper.java
index 0cdecd1..26f8003 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/DomainEventHelper.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/DomainEventHelper.java
@@ -133,8 +133,7 @@ public class DomainEventHelper {
// no-arg constructor
for (final Constructor<?> constructor : constructors) {
- final Class<?>[] parameterTypes = constructor.getParameterTypes();
- if(parameterTypes.length == 0) {
+ if(constructor.getParameterCount() == 0) {
final Object event = constructor.newInstance();
final ActionDomainEvent<S> ade = uncheckedCast(event);
@@ -231,8 +230,7 @@ public class DomainEventHelper {
// no-arg constructor
for (final Constructor<?> constructor : constructors) {
- final Class<?>[] parameterTypes = constructor.getParameterTypes();
- if(parameterTypes.length == 0) {
+ if(constructor.getParameterCount() == 0) {
final Object event = constructor.newInstance();
final PropertyDomainEvent<S, T> pde = uncheckedCast(event);
pde.initSource(source);
@@ -320,8 +318,7 @@ public class DomainEventHelper {
// no-arg constructor
for (final Constructor<?> constructor : constructors) {
- final Class<?>[] parameterTypes = constructor.getParameterTypes();
- if(parameterTypes.length ==0) {
+ if(constructor.getParameterCount() == 0) {
final Object event = constructor.newInstance();
final CollectionDomainEvent<S, T> cde = uncheckedCast(event);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactory.java
index ee92f1f..75e7b9f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactory.java
@@ -219,6 +219,8 @@ public interface FacetFactory {
public static class ProcessParameterContext extends AbstractProcessWithMethodContext<FacetedMethodParameter> {
private final int paramNum;
+ private final Class<?> paramType;
+ private final Parameter parameter;
public ProcessParameterContext(
final Class<?> cls,
@@ -232,6 +234,8 @@ public interface FacetFactory {
throw _Exceptions.unrecoverable("invalid ProcessParameterContext");
}
this.paramNum = paramNum;
+ this.paramType = super.method.getParameterTypes()[paramNum];
+ this.parameter = super.method.getParameters()[paramNum];
}
public int getParamNum() {
@@ -243,21 +247,21 @@ public interface FacetFactory {
* @since 2.0
*/
public <A extends Annotation> Optional<A> synthesizeOnParameter(Class<A> annotationType) {
- return _Annotations.synthesizeInherited(getParameter(), annotationType);
+ return _Annotations.synthesizeInherited(parameter, annotationType);
}
/**
* @since 2.0
*/
public Class<?> getParameterType() {
- return super.method.getParameterTypes()[paramNum];
+ return this.paramType;
}
/**
* @since 2.0
*/
public Parameter getParameter() {
- return super.method.getParameters()[paramNum];
+ return parameter;
}
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java
index c771718..d5214c0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java
@@ -33,8 +33,6 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.isis.commons.internal.collections._Lists;
import org.apache.isis.config.IsisConfiguration;
-import org.apache.isis.config.IsisConfigurationLegacy;
-import org.apache.isis.config.internal._Config;
import org.apache.isis.metamodel.facetapi.FacetHolder;
import org.apache.isis.metamodel.facetapi.FacetUtil;
import org.apache.isis.metamodel.facetapi.FeatureType;
@@ -366,7 +364,7 @@ implements MetaModelValidatorRefiner {
final Class<?> correspondingClass = objectSpec.getCorrespondingClass();
final Constructor<?>[] constructors = correspondingClass.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
- if(constructor.getParameterTypes().length == 0) {
+ if(constructor.getParameterCount() == 0) {
if (!Modifier.isPublic(constructor.getModifiers())) {
validationFailures
.add(objectSpec.getIdentifier(),
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/disabled/forsession/DisableForSessionFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/disabled/forsession/DisableForSessionFacetViaMethod.java
index 511652d..9457c9c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/disabled/forsession/DisableForSessionFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/disabled/forsession/DisableForSessionFacetViaMethod.java
@@ -63,7 +63,7 @@ public class DisableForSessionFacetViaMethod extends DisableForSessionFacetAbstr
if (session == null) {
return null;
}
- final int len = method.getParameterTypes().length;
+ final int len = method.getParameterCount();
final Object[] parameters = new Object[len];
parameters[0] = session.createUserMemento();
// TODO: need to change to pick up as non-static rather than static
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/forsession/HideForSessionFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/forsession/HideForSessionFacetViaMethod.java
index 0af1d0b..2b51850 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/forsession/HideForSessionFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/forsession/HideForSessionFacetViaMethod.java
@@ -63,7 +63,7 @@ public class HideForSessionFacetViaMethod extends HideForSessionFacetAbstract im
if (session == null) {
return null;
}
- final int len = method.getParameterTypes().length;
+ final int len = method.getParameterCount();
final Object[] parameters = new Object[len];
parameters[0] = session.createUserMemento();
// TODO: need to change to pick up as non-static rather than static
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java
index 1011638..cfea71a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java
@@ -34,6 +34,8 @@ import org.apache.isis.metamodel.facets.param.choices.ActionChoicesFacetAbstract
import org.apache.isis.metamodel.spec.DomainModelException;
import org.apache.isis.metamodel.spec.ObjectSpecification;
+import lombok.val;
+
public class ActionChoicesFacetViaMethod extends ActionChoicesFacetAbstract implements ImperativeFacet {
private final Method method;
@@ -77,10 +79,10 @@ public class ActionChoicesFacetViaMethod extends ActionChoicesFacetAbstract impl
final Object[] options = (Object[]) objectOrCollection;
final Object[][] results = new Object[options.length][];
+ val parameterTypes = method.getParameterTypes();
+
for (int i = 0; i < results.length; i++) {
- final Class<?> parameterType = method.getParameterTypes()[i];
- results[i] = handleResults(options[i], parameterType,
- interactionInitiatedBy);
+ results[i] = handleResults(options[i], parameterTypes[i], interactionInitiatedBy);
}
return results;
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethodFactory.java
index fb326b7..6282e84 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethodFactory.java
@@ -58,9 +58,8 @@ public class ActionChoicesFacetViaMethodFactory extends MethodPrefixBasedFacetFa
private void attachActionChoicesFacetIfParameterChoicesMethodIsFound(final ProcessMethodContext processMethodContext) {
final Method actionMethod = processMethodContext.getMethod();
- final Class<?>[] actionParamTypes = actionMethod.getParameterTypes();
- if (actionParamTypes.length <= 0) {
+ if (actionMethod.getParameterCount() <= 0) {
return;
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java
index 515a134..da32a96 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java
@@ -78,7 +78,7 @@ public class ActionParameterDefaultsFacetViaMethod extends ActionParameterDefaul
// this could be a dependent defaults situation, but has a previous parameter been updated
// that this parameter is dependent upon?
- final int numParams = method.getParameterTypes().length;
+ final int numParams = method.getParameterCount();
if (paramNumUpdated < numParams) {
// in this case the parameter that was updated is previous
//
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java
index 1f45c41..b731a50 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java
@@ -73,9 +73,9 @@ public class ActionParameterDefaultsFacetViaMethodFactory extends MethodPrefixBa
}
final Method actionMethod = processMethodContext.getMethod();
- final Class<?>[] paramTypes = actionMethod.getParameterTypes();
+ final int paramCount = actionMethod.getParameterCount();
- for (int i = 0; i < paramTypes.length; i++) {
+ for (int i = 0; i < paramCount; i++) {
// attempt to match method...
Method defaultMethod = findDefaultNumMethod(processMethodContext, i);
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/SpecloaderPerformanceTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/SpecloaderPerformanceTest.java
index 9fd1e1b..3181ac6 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/SpecloaderPerformanceTest.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/SpecloaderPerformanceTest.java
@@ -18,8 +18,6 @@
*/
package org.apache.isis.testdomain.domainmodel;
-import java.time.Duration;
-
import javax.inject.Inject;
import org.junit.jupiter.api.BeforeAll;
@@ -27,6 +25,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
+import org.apache.isis.commons.internal.base._Timing;
+import org.apache.isis.commons.internal.reflection._Annotations;
import org.apache.isis.config.IsisConfiguration;
import org.apache.isis.config.IsisPresets;
import org.apache.isis.config.registry.IsisBeanTypeRegistry;
@@ -36,7 +36,7 @@ import org.apache.isis.testdomain.Smoketest;
import org.apache.isis.testdomain.conf.Configuration_headless;
import org.apache.isis.testdomain.model.good.Configuration_usingValidDomain;
-import static org.junit.jupiter.api.Assertions.assertTimeout;
+import static org.junit.jupiter.api.Assertions.fail;
import lombok.val;
@@ -66,7 +66,7 @@ class SpecloaderPerformanceTest {
IsisBeanTypeRegistry.repeatedTesting = true;
}
- static long ITERATIONS = 40; /* should typically run in ~10s */
+ static long ITERATIONS = 400; /* should typically run in ~10s */
static long EXPECTED_MILLIS_PER_ITERATION = 500;
@Test
@@ -75,17 +75,23 @@ class SpecloaderPerformanceTest {
config.getReflector().getIntrospector().setParallelize(true);
val timeOutMillis = ITERATIONS * EXPECTED_MILLIS_PER_ITERATION;
+ val goodUntilMillis = System.currentTimeMillis() + timeOutMillis;
- assertTimeout(Duration.ofMillis(timeOutMillis), ()->{
+ val repeatedRun = (Runnable)()->{
for(int i=0; i<ITERATIONS; ++i) {
+ _Annotations.clearCache();
specificationLoader.shutdown();
specificationLoader.init();
+
+ if(System.currentTimeMillis() > goodUntilMillis) {
+ fail("timed out");
+ }
}
- });
-
+ };
+ _Timing.runVerbose("Repeated Concurrent Specloading", repeatedRun);
}