diff --git a/src/main/java/spoon/metamodel/Metamodel.java b/src/main/java/spoon/metamodel/Metamodel.java index 0ec0da0116d..ca8b0bce986 100644 --- a/src/main/java/spoon/metamodel/Metamodel.java +++ b/src/main/java/spoon/metamodel/Metamodel.java @@ -209,6 +209,16 @@ public static Set> getAllMetamodelInterfaces() { */ public static Metamodel getInstance() { if (instance == null) { + try { + //this is needed just for CtGenerationTest#testGenerateRoleHandler + //which must not use RoleHandler at time when RoleHandler is generated and Spoon model doesn't fit to old RoleHandlers + //to avoid egg/chicken problem + if ("true".equals(System.getProperty(MetamodelProperty.class.getName() + "-noRoleHandler"))) { + MetamodelProperty.useRuntimeMethodInvocation = true; + } + } catch (SecurityException e) { + //ignore that + } instance = new Metamodel(); } return instance; diff --git a/src/main/java/spoon/metamodel/MetamodelProperty.java b/src/main/java/spoon/metamodel/MetamodelProperty.java index 5eadbaec370..1ac878a8c29 100644 --- a/src/main/java/spoon/metamodel/MetamodelProperty.java +++ b/src/main/java/spoon/metamodel/MetamodelProperty.java @@ -19,6 +19,8 @@ import static spoon.metamodel.Metamodel.addUniqueObject; import static spoon.metamodel.Metamodel.getOrCreate; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -39,6 +41,7 @@ import spoon.reflect.reference.CtTypeReference; import spoon.support.DerivedProperty; import spoon.support.UnsettableProperty; +import spoon.support.util.RtHelper; /** * Represents a property of the Spoon metamodel. @@ -587,11 +590,27 @@ public RoleHandler getRoleHandler() { return roleHandler; } + static boolean useRuntimeMethodInvocation = false; + /** * @param element an instance whose attribute value is read * @return a value of attribute defined by this {@link MetamodelProperty} from the provided `element` */ public U getValue(T element) { + if (useRuntimeMethodInvocation) { + MMMethod method = getMethod(MMMethodKind.GET); + if (method != null) { + Method rtMethod = RtHelper.getMethod(getOwner().getImplementationClass().getActualClass(), method.getName(), 0); + if (rtMethod != null) { + try { + return (U) rtMethod.invoke(element); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new SpoonException("Invokation of getter on " + toString() + " failed", e); + } + } + throw new SpoonException("Cannot invoke getter on " + toString()); + } + } return getRoleHandler().getValue(element); } @@ -600,6 +619,21 @@ public U getValue(T element) { * @param value to be set value of attribute defined by this {@link MetamodelProperty} on the provided `element` */ public void setValue(T element, U value) { + if (useRuntimeMethodInvocation) { + MMMethod method = getMethod(MMMethodKind.SET); + if (method != null) { + Method rtMethod = RtHelper.getMethod(getOwner().getImplementationClass().getActualClass(), method.getName(), 1); + if (rtMethod != null) { + try { + rtMethod.invoke(element, value); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new SpoonException("Invokation of setter on " + toString() + " failed", e); + } + return; + } + throw new SpoonException("Cannot invoke setter on " + toString()); + } + } getRoleHandler().setValue(element, value); } } diff --git a/src/test/java/spoon/processing/CtGenerationTest.java b/src/test/java/spoon/processing/CtGenerationTest.java index 68e22c7bf86..6f6e9a13bff 100644 --- a/src/test/java/spoon/processing/CtGenerationTest.java +++ b/src/test/java/spoon/processing/CtGenerationTest.java @@ -7,6 +7,7 @@ import spoon.generating.CtBiScannerGenerator; import spoon.generating.ReplacementVisitorGenerator; import spoon.generating.RoleHandlersGenerator; +import spoon.metamodel.MetamodelProperty; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtType; import spoon.reflect.visitor.CtBiScannerDefault; @@ -173,7 +174,12 @@ public void testGenerateRoleHandler() throws Exception { launcher.addInputResource("./src/main/java/spoon/reflect/meta/impl/AbstractRoleHandler.java"); launcher.addProcessor(new RoleHandlersGenerator()); launcher.setOutputFilter(new RegexFilter("\\Q" + RoleHandlersGenerator.TARGET_PACKAGE + ".ModelRoleHandlers\\E.*")); - launcher.run(); + try { + System.setProperty(MetamodelProperty.class.getName()+"-noRoleHandler", "true"); + launcher.run(); + } finally { + System.setProperty(MetamodelProperty.class.getName()+"-noRoleHandler", "false"); + } // cp ./target/generated/spoon/reflect/meta/impl/ModelRoleHandlers.java ./src/main/java/spoon/reflect/meta/impl/ModelRoleHandlers.java CtClass actual = build(new File(launcher.getModelBuilder().getSourceOutputDirectory()+"/spoon/reflect/meta/impl/ModelRoleHandlers.java")).Class().get("spoon.reflect.meta.impl.ModelRoleHandlers");