Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(CoreFactory): add create(Class) so as to create elements by reflection #949

Merged
merged 1 commit into from
Nov 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/main/java/spoon/reflect/factory/CoreFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,8 @@ public interface CoreFactory {
* Recursively clones a given element of the metamodel and all its child
* elements.
*
* @param <T>
* the element's type
* @param element
* the element
* @param <T> the element's type
* @param element the element
* @return a clone of <code>element</code>
* @see spoon.reflect.declaration.CtElement#clone()
*/
Expand Down Expand Up @@ -496,4 +494,11 @@ SourcePosition createSourcePosition(
* Creates an unbound variable used in noclasspath.
*/
<T> CtUnboundVariableReference<T> createUnboundVariableReference();

/**
* Creates an instance of the concrete metamodel class given as parameter.
*
* This is in particular useful when one uses reflection.
*/
CtElement create(Class<? extends CtElement> klass);
}
217 changes: 217 additions & 0 deletions src/main/java/spoon/support/DefaultCoreFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -659,4 +659,221 @@ public <T> CtSuperAccess<T> createSuperAccess() {
return e;
}

public CtElement create(Class<? extends CtElement> klass) {
if (klass.equals(spoon.reflect.code.CtAnnotationFieldAccess.class)) {
return createAnnotationFieldAccess();
}
if (klass.equals(spoon.reflect.code.CtArrayRead.class)) {
return createArrayRead();
}
if (klass.equals(spoon.reflect.code.CtArrayWrite.class)) {
return createArrayWrite();
}
if (klass.equals(spoon.reflect.code.CtAssert.class)) {
return createAssert();
}
if (klass.equals(spoon.reflect.code.CtAssignment.class)) {
return createAssignment();
}
if (klass.equals(spoon.reflect.code.CtBinaryOperator.class)) {
return createBinaryOperator();
}
if (klass.equals(spoon.reflect.code.CtBlock.class)) {
return createBlock();
}
if (klass.equals(spoon.reflect.code.CtBreak.class)) {
return createBreak();
}
if (klass.equals(spoon.reflect.code.CtCase.class)) {
return createCase();
}
if (klass.equals(spoon.reflect.code.CtCatch.class)) {
return createCatch();
}
if (klass.equals(spoon.reflect.code.CtCatchVariable.class)) {
return createCatchVariable();
}
if (klass.equals(spoon.reflect.code.CtCodeSnippetExpression.class)) {
return createCodeSnippetExpression();
}
if (klass.equals(spoon.reflect.code.CtCodeSnippetStatement.class)) {
return createCodeSnippetStatement();
}
if (klass.equals(spoon.reflect.code.CtComment.class)) {
return createComment();
}
if (klass.equals(spoon.reflect.code.CtConditional.class)) {
return createConditional();
}
if (klass.equals(spoon.reflect.code.CtConstructorCall.class)) {
return createConstructorCall();
}
if (klass.equals(spoon.reflect.code.CtContinue.class)) {
return createContinue();
}
if (klass.equals(spoon.reflect.code.CtDo.class)) {
return createDo();
}
if (klass.equals(spoon.reflect.code.CtExecutableReferenceExpression.class)) {
return createExecutableReferenceExpression();
}
if (klass.equals(spoon.reflect.code.CtFieldRead.class)) {
return createFieldRead();
}
if (klass.equals(spoon.reflect.code.CtFieldWrite.class)) {
return createFieldWrite();
}
if (klass.equals(spoon.reflect.code.CtForEach.class)) {
return createForEach();
}
if (klass.equals(spoon.reflect.code.CtFor.class)) {
return createFor();
}
if (klass.equals(spoon.reflect.code.CtIf.class)) {
return createIf();
}
if (klass.equals(spoon.reflect.code.CtInvocation.class)) {
return createInvocation();
}
if (klass.equals(spoon.reflect.code.CtLambda.class)) {
return createLambda();
}
if (klass.equals(spoon.reflect.code.CtLiteral.class)) {
return createLiteral();
}
if (klass.equals(spoon.reflect.code.CtLocalVariable.class)) {
return createLocalVariable();
}
if (klass.equals(spoon.reflect.code.CtNewArray.class)) {
return createNewArray();
}
if (klass.equals(spoon.reflect.code.CtNewClass.class)) {
return createNewClass();
}
if (klass.equals(spoon.reflect.code.CtOperatorAssignment.class)) {
return createOperatorAssignment();
}
if (klass.equals(spoon.reflect.code.CtReturn.class)) {
return createReturn();
}
if (klass.equals(spoon.reflect.code.CtStatementList.class)) {
return createStatementList();
}
if (klass.equals(spoon.reflect.code.CtSuperAccess.class)) {
return createSuperAccess();
}
if (klass.equals(spoon.reflect.code.CtSwitch.class)) {
return createSwitch();
}
if (klass.equals(spoon.reflect.code.CtSynchronized.class)) {
return createSynchronized();
}
if (klass.equals(spoon.reflect.code.CtThisAccess.class)) {
return createThisAccess();
}
if (klass.equals(spoon.reflect.code.CtThrow.class)) {
return createThrow();
}
if (klass.equals(spoon.reflect.code.CtTry.class)) {
return createTry();
}
if (klass.equals(spoon.reflect.code.CtTryWithResource.class)) {
return createTryWithResource();
}
if (klass.equals(spoon.reflect.code.CtTypeAccess.class)) {
return createTypeAccess();
}
if (klass.equals(spoon.reflect.code.CtUnaryOperator.class)) {
return createUnaryOperator();
}
if (klass.equals(spoon.reflect.code.CtVariableRead.class)) {
return createVariableRead();
}
if (klass.equals(spoon.reflect.code.CtVariableWrite.class)) {
return createVariableWrite();
}
if (klass.equals(spoon.reflect.code.CtWhile.class)) {
return createWhile();
}
if (klass.equals(spoon.reflect.declaration.CtAnnotation.class)) {
return createAnnotation();
}
if (klass.equals(spoon.reflect.declaration.CtAnnotationMethod.class)) {
return createAnnotationMethod();
}
if (klass.equals(spoon.reflect.declaration.CtAnnotationType.class)) {
return createAnnotationType();
}
if (klass.equals(spoon.reflect.declaration.CtAnonymousExecutable.class)) {
return createAnonymousExecutable();
}
if (klass.equals(spoon.reflect.declaration.CtClass.class)) {
return createClass();
}
if (klass.equals(spoon.reflect.declaration.CtConstructor.class)) {
return createConstructor();
}
if (klass.equals(spoon.reflect.declaration.CtEnum.class)) {
return createEnum();
}
if (klass.equals(spoon.reflect.declaration.CtEnumValue.class)) {
return createEnumValue();
}
if (klass.equals(spoon.reflect.declaration.CtField.class)) {
return createField();
}
if (klass.equals(spoon.reflect.declaration.CtInterface.class)) {
return createInterface();
}
if (klass.equals(spoon.reflect.declaration.CtMethod.class)) {
return createMethod();
}
if (klass.equals(spoon.reflect.declaration.CtPackage.class)) {
return createPackage();
}
if (klass.equals(spoon.reflect.declaration.CtParameter.class)) {
return createParameter();
}
if (klass.equals(spoon.reflect.declaration.CtTypeParameter.class)) {
return createTypeParameter();
}
if (klass.equals(spoon.reflect.reference.CtArrayTypeReference.class)) {
return createArrayTypeReference();
}
if (klass.equals(spoon.reflect.reference.CtCatchVariableReference.class)) {
return createCatchVariableReference();
}
if (klass.equals(spoon.reflect.reference.CtExecutableReference.class)) {
return createExecutableReference();
}
if (klass.equals(spoon.reflect.reference.CtFieldReference.class)) {
return createFieldReference();
}
if (klass.equals(spoon.reflect.reference.CtIntersectionTypeReference.class)) {
return createIntersectionTypeReference();
}
if (klass.equals(spoon.reflect.reference.CtLocalVariableReference.class)) {
return createLocalVariableReference();
}
if (klass.equals(spoon.reflect.reference.CtPackageReference.class)) {
return createPackageReference();
}
if (klass.equals(spoon.reflect.reference.CtParameterReference.class)) {
return createParameterReference();
}
if (klass.equals(spoon.reflect.reference.CtTypeParameterReference.class)) {
return createTypeParameterReference();
}
if (klass.equals(spoon.reflect.reference.CtTypeReference.class)) {
return createTypeReference();
}
if (klass.equals(spoon.reflect.reference.CtUnboundVariableReference.class)) {
return createUnboundVariableReference();
}
if (klass.equals(spoon.reflect.reference.CtWildcardReference.class)) {
return createWildcardReference();
}
throw new IllegalArgumentException("not instantiable by CoreFactory()");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ public class CtInheritanceScannerTest<T extends CtVisitable> {
public static Collection<Object[]> data() throws Exception {
List<Object[]> values = new ArrayList<>();
for (Method method : CoreFactory.class.getDeclaredMethods()) {
if (method.getName().startsWith("create") && method.getReturnType().getSimpleName().startsWith("Ct")) {
if (method.getName().startsWith("create")
&& method.getParameterCount() == 0
Copy link
Collaborator

@tdurieux tdurieux Nov 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why to you change this test?

&& method.getReturnType().getSimpleName().startsWith("Ct")) {
values.add(new Object[] { method.getReturnType(), method.invoke(factory.Core()) });
}
}
Expand Down
44 changes: 44 additions & 0 deletions src/test/java/spoon/test/SpoonTestHelpers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package spoon.test;

import spoon.Launcher;
import spoon.SpoonAPI;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.ModifierKind;

import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

public class SpoonTestHelpers {
// only static methods
private SpoonTestHelpers(){
}

public static List<CtType<? extends CtElement>> getAllInstantiableMetamodelInterfaces() {
List<CtType<? extends CtElement>> result = new ArrayList<>();
SpoonAPI interfaces = new Launcher();
interfaces.addInputResource("src/main/java/spoon/reflect/declaration");
interfaces.addInputResource("src/main/java/spoon/reflect/code");
interfaces.addInputResource("src/main/java/spoon/reflect/reference");
interfaces.buildModel();

SpoonAPI implementations = new Launcher();
implementations.addInputResource("src/main/java/spoon/support/reflect/declaration");
implementations.addInputResource("src/main/java/spoon/support/reflect/code");
implementations.addInputResource("src/main/java/spoon/support/reflect/reference");
implementations.buildModel();

for(CtType<? > itf : interfaces.getModel().getAllTypes()) {
String impl = itf.getQualifiedName().replace("spoon.reflect", "spoon.support.reflect")+"Impl";
CtType implClass = implementations.getFactory().Type().get(impl);
if (implClass != null && !implClass.hasModifier(ModifierKind.ABSTRACT)) {
result.add((CtType<? extends CtElement>) itf);
}
}
return result;
}
}
14 changes: 14 additions & 0 deletions src/test/java/spoon/test/factory/FactoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import spoon.reflect.code.CtFieldRead;
import spoon.reflect.code.CtNewArray;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.factory.CoreFactory;
import spoon.reflect.factory.Factory;
import spoon.reflect.factory.FactoryImpl;
Expand All @@ -20,10 +22,12 @@
import spoon.support.DefaultCoreFactory;
import spoon.support.StandardEnvironment;
import spoon.support.reflect.declaration.CtMethodImpl;
import spoon.test.SpoonTestHelpers;
import spoon.test.factory.testclasses.Foo;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static spoon.testing.utils.ModelUtils.build;
Expand Down Expand Up @@ -185,4 +189,14 @@ public boolean matches(CtPackage element) {
}).size());
}

@Test
public void specificationCoreFactoryCreate() throws Exception {
// contract: all concrete metamodel classes must be instantiable by CoreFactory.create
for(CtType<? extends CtElement> itf : SpoonTestHelpers.getAllInstantiableMetamodelInterfaces()) {
CtElement o = itf.getFactory().Core().create(itf.getActualClass());
assertNotNull(o);
assertTrue(itf.getActualClass().isInstance(o));
}
}

}
1 change: 1 addition & 0 deletions src/test/java/spoon/test/parent/ParentContractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public static Collection<Object[]> data() throws Exception {
List<Object[]> values = new ArrayList<>();
for (Method method : CoreFactory.class.getDeclaredMethods()) {
if (method.getName().startsWith("create")
&& method.getParameterCount() == 0
&& method.getReturnType().getSimpleName().startsWith("Ct")
&& !CtReference.class.isAssignableFrom(method.getReturnType())
){
Expand Down