![JAR search and dependency download from the Maven repository](/logo.png)
org.nasdanika.common.ReflectiveFeatureMapper Maven / Gradle / Ivy
package org.nasdanika.common;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
/**
* Content mapper which uses annotations for wiring
* @param
* @param
*/
public class ReflectiveFeatureMapper extends FeatureMapper implements EStructuralFeatureAndEOperationMatcher {
/**
* Annotation for feature wiring methods.
* Methods shall have the same parameters as {@link FeatureMapper}.wireFeature().
* Methods are matched by annotation xxxType() values and by method parameter types.
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface Feature {
/**
* Target feature id
*/
int value();
int classID();
String nsURI();
/**
* If not blank, the value shall be a Spring boolean expression
* which is evaluated in the context of the source element with other method arguments as variables
* @return
*/
String condition() default "";
/**
* Matching by source type.
* @return
*/
Class> type() default Object.class;
/**
* Matching by value (target) type.
* @return
*/
Class> valueType() default Object.class;
/**
* Wire priority within the phase
* @return
*/
int priority() default 0;
}
/**
* Annotation for feature wiring methods.
* Methods shall have the same parameters as {@link FeatureMapper}.wireContainerFeature().
* Methods are matched by annotation xxxType() values and by method parameter types.
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface ContainerFeature {
/**
* Feature id
*/
int value();
int classID();
String nsURI();
/**
* If not blank, the value shall be a Spring boolean expression
* which is evaluated in the context of the source element with other method arguments as variables
* @return
*/
String condition() default "";
/**
* Matching by container source type.
* @return
*/
Class> containerType() default Object.class;
/**
* Matching by container value (target) type.
* @return
*/
Class> containerValueType() default Object.class;
/**
* Matching by contents (source) type.
* @return
*/
Class> contentsType() default Object.class;
/**
* Matching by contents value (target) type.
* @return
*/
Class> contentsValueType() default Object.class;
/**
* Wire priority within the phase
* @return
*/
int priority() default 0;
}
/**
* Annotation for feature wiring methods.
* Methods shall have the same parameters as {@link FeatureMapper}.wireContentsFeature().
* Methods are matched by annotation xxxType() values and by method parameter types.
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface ContentsFeature {
/**
* Feature id
*/
int value();
int classID();
String nsURI();
/**
* If not blank, the value shall be a Spring boolean expression
* which is evaluated in the context of the source element with other method arguments as variables
* @return
*/
String condition() default "";
/**
* Matching by container source type.
* @return
*/
Class> containerType() default Object.class;
/**
* Matching by container value (target) type.
* @return
*/
Class> containerValueType() default Object.class;
/**
* Matching by contents (source) type.
* @return
*/
Class> contentsType() default Object.class;
/**
* Matching by contents value (target) type.
* @return
*/
Class> contentsValueType() default Object.class;
/**
* Wire priority within the phase
* @return
*/
int priority() default 0;
}
/**
* Annotation for feature wiring methods.
* Methods shall have the same parameters as {@link FeatureMapper}.wireChildFeature().
* Methods are matched by annotation xxxType() values and by method parameter types.
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface ConnectionStartFeature {
/**
* Feature id
*/
int value();
int classID();
String nsURI();
/**
* If not blank, the value shall be a Spring boolean expression
* which is evaluated in the context of the source element with other method arguments as variables
* @return
*/
String condition() default "";
/**
* Matching by connection (source) type.
* @return
*/
Class> connectionType() default Object.class;
/**
* Matching by connection value (target) type.
* @return
*/
Class> connectionValueType() default Object.class;
/**
* Matching by connection source type.
* @return
*/
Class> sourceType() default Object.class;
/**
* Matching by connection source value (target) type.
* @return
*/
Class> sourceValueType() default Object.class;
/**
* Wire priority within the phase
* @return
*/
int priority() default 0;
}
/**
* Annotation for feature wiring methods.
* Methods shall have the same parameters as {@link FeatureMapper}.wireChildFeature().
* Methods are matched by annotation xxxType() values and by method parameter types.
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface ConnectionEndFeature {
/**
* Feature id
*/
int value();
int classID();
String nsURI();
/**
* If not blank, the value shall be a Spring boolean expression
* which is evaluated in the context of the source element with other method arguments as variables
* @return
*/
String condition() default "";
/**
* Matching by connection (source) type.
* @return
*/
Class> connectionType() default Object.class;
/**
* Matching by connection value (target) type.
* @return
*/
Class> connectionValueType() default Object.class;
/**
* Matching by connection source type.
* @return
*/
Class> targetType() default Object.class;
/**
* Matching by connection source value (target) type.
* @return
*/
Class> targetValueType() default Object.class;
/**
* Wire priority within the phase
* @return
*/
int priority() default 0;
}
/**
* Annotation for feature wiring methods.
* Methods shall have the same parameters as {@link FeatureMapper}.wireChildFeature().
* Methods are matched by annotation xxxType() values and by method parameter types.
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface ConnectionSourceFeature {
/**
* Feature id
*/
int value();
int classID();
String nsURI();
/**
* If not blank, the value shall be a Spring boolean expression
* which is evaluated in the context of the source element with other method arguments as variables
* @return
*/
String condition() default "";
/**
* Matching by connection (source) type.
* @return
*/
Class> connectionType() default Object.class;
/**
* Matching by connection value (target) type.
* @return
*/
Class> connectionValueType() default Object.class;
/**
* Matching by connection source type.
* @return
*/
Class> sourceType() default Object.class;
/**
* Matching by connection source value (target) type.
* @return
*/
Class> sourceValueType() default Object.class;
/**
* Wire priority within the phase
* @return
*/
int priority() default 0;
}
/**
* Annotation for feature wiring methods.
* Methods shall have the same parameters as {@link FeatureMapper}.wireChildFeature().
* Methods are matched by annotation xxxType() values and by method parameter types.
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface ConnectionTargetFeature {
/**
* Feature id
*/
int value();
int classID();
String nsURI();
/**
* If not blank, the value shall be a Spring boolean expression
* which is evaluated in the context of the source element with other method arguments as variables
* @return
*/
String condition() default "";
/**
* Matching by connection (source) type.
* @return
*/
Class> connectionType() default Object.class;
/**
* Matching by connection value (target) type.
* @return
*/
Class> connectionValueType() default Object.class;
/**
* Matching by connection source type.
* @return
*/
Class> targetType() default Object.class;
/**
* Matching by connection source value (target) type.
* @return
*/
Class> targetValueType() default Object.class;
/**
* Wire priority within the phase
* @return
*/
int priority() default 0;
}
protected class Dispatcher extends Reflector {
protected List featureWires = new ArrayList<>();
protected List containerFeatureWires = new ArrayList<>();
protected List contentsFeatureWires = new ArrayList<>();
protected List connectionSourceFeatureWires = new ArrayList<>();
protected List connectionStartFeatureWires = new ArrayList<>();
protected List connectionTargetFeatureWires = new ArrayList<>();
protected List connectionEndFeatureWires = new ArrayList<>();
public Dispatcher(Object[] targets) {
for (Object target: targets) {
getAnnotatedElementRecords(target, Collections.singletonList(target))
.filter(ar -> ar.getAnnotation(Feature.class) != null && ar.getAnnotatedElement() instanceof Method)
.sorted((a,b) -> b.getAnnotation(Feature.class).priority() - a.getAnnotation(Feature.class).priority())
.forEach(featureWires::add);
getAnnotatedElementRecords(target, Collections.singletonList(target))
.filter(ar -> ar.getAnnotation(ContainerFeature.class) != null && ar.getAnnotatedElement() instanceof Method)
.sorted((a,b) -> b.getAnnotation(ContainerFeature.class).priority() - a.getAnnotation(ContainerFeature.class).priority())
.forEach(containerFeatureWires::add);
getAnnotatedElementRecords(target, Collections.singletonList(target))
.filter(ar -> ar.getAnnotation(ContentsFeature.class) != null && ar.getAnnotatedElement() instanceof Method)
.sorted((a,b) -> b.getAnnotation(ContentsFeature.class).priority() - a.getAnnotation(ContentsFeature.class).priority())
.forEach(contentsFeatureWires::add);
getAnnotatedElementRecords(target, Collections.singletonList(target))
.filter(ar -> ar.getAnnotation(ConnectionSourceFeature.class) != null && ar.getAnnotatedElement() instanceof Method)
.sorted((a,b) -> b.getAnnotation(ConnectionSourceFeature.class).priority() - a.getAnnotation(ConnectionSourceFeature.class).priority())
.forEach(connectionSourceFeatureWires::add);
getAnnotatedElementRecords(target, Collections.singletonList(target))
.filter(ar -> ar.getAnnotation(ConnectionStartFeature.class) != null && ar.getAnnotatedElement() instanceof Method)
.sorted((a,b) -> b.getAnnotation(ConnectionStartFeature.class).priority() - a.getAnnotation(ConnectionStartFeature.class).priority())
.forEach(connectionStartFeatureWires::add);
getAnnotatedElementRecords(target, Collections.singletonList(target))
.filter(ar -> ar.getAnnotation(ConnectionTargetFeature.class) != null && ar.getAnnotatedElement() instanceof Method)
.sorted((a,b) -> b.getAnnotation(ConnectionTargetFeature.class).priority() - a.getAnnotation(ConnectionTargetFeature.class).priority())
.forEach(contentsFeatureWires::add);
getAnnotatedElementRecords(target, Collections.singletonList(target))
.filter(ar -> ar.getAnnotation(ConnectionEndFeature.class) != null && ar.getAnnotatedElement() instanceof Method)
.sorted((a,b) -> b.getAnnotation(ConnectionEndFeature.class).priority() - a.getAnnotation(ConnectionEndFeature.class).priority())
.forEach(contentsFeatureWires::add);
}
}
protected void wireFeature(
S source,
T value,
EStructuralFeature valueFeature,
Map registry,
ProgressMonitor progressMonitor) {
for (AnnotatedElementRecord ar: featureWires) {
Feature rWire = ar.getAnnotation(Feature.class);
Class>[] parameterTypes = ((Method) ar.getAnnotatedElement()).getParameterTypes();
if (rWire.type().isInstance(source) && parameterTypes[0].isInstance(source)
&& (rWire.valueType() == Void.class ? value == null : rWire.valueType().isInstance(value) && parameterTypes[1].isInstance(value))
// String nsURI, int classID, int featureID, EClass contextEClass, EStructuralFeature feature
&& matchEStructuralFeature(rWire.nsURI(), rWire.classID(), rWire.value(), value == null ? null : value.eClass(), valueFeature)) {
Map variables = new HashMap<>();
variables.put("registry", registry);
if (evaluatePredicate(source, rWire.condition(), variables)) {
ar.invoke(source, value, registry, progressMonitor);
}
}
}
}
protected boolean wireContentsFeature(
S contents,
T contentsValue,
EStructuralFeature contentsValueFeature,
S container,
T containerValue,
LinkedList sourcePath,
Map registry,
ProgressMonitor progressMonitor) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy