From 1b99d909cf73edd8486d57b5ba6263dff6544cd7 Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Thu, 19 Nov 2015 14:52:35 +0100 Subject: [PATCH 1/2] fix(executable): Supports CtConstructorCall in noclasspath mode. Closes #405 --- .../support/compiler/jdt/JDTTreeBuilder.java | 18 ++- .../test/executable/ExecutableRefTest.java | 34 ++++- .../resources/executable/CmiContext_1.2.java | 118 ++++++++++++++++++ 3 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 src/test/resources/executable/CmiContext_1.2.java diff --git a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java index d1e83bccc46..f976dda4c36 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java @@ -1673,9 +1673,23 @@ private > T buildCommonPartForCtNewClassAndC } else if (allocationExpression.expectedType() != null) { constructorCall.setType(references.getTypeReference(allocationExpression.expectedType())); } - constructorCall.setExecutable(references.getExecutableReference(allocationExpression.binding)); + if (allocationExpression.binding != null) { + constructorCall.setExecutable(references.getExecutableReference(allocationExpression.binding)); + } else { + final CtExecutableReference ref = factory.Core().createExecutableReference(); + ref.setSimpleName(CtExecutableReference.CONSTRUCTOR_NAME); + ref.setType(references.getTypeReference(null, allocationExpression.type)); + ref.setDeclaringType(references.getTypeReference(null, allocationExpression.type)); + + final List> parameters = new ArrayList>(allocationExpression.argumentTypes.length); + for (TypeBinding b : allocationExpression.argumentTypes) { + parameters.add(references.getTypeReference(b)); + } + ref.setParameters(parameters); + constructorCall.setExecutable(ref); + } if (constructorCall.getExecutable() != null) { - constructorCall.getExecutable().setType((CtTypeReference) constructorCall.getExecutable().getDeclaringType()); + constructorCall.getExecutable().setType(constructorCall.getType()); } if (allocationExpression.genericTypeArguments() != null) { diff --git a/src/test/java/spoon/test/executable/ExecutableRefTest.java b/src/test/java/spoon/test/executable/ExecutableRefTest.java index 4f208202185..fe1dde1f4c3 100644 --- a/src/test/java/spoon/test/executable/ExecutableRefTest.java +++ b/src/test/java/spoon/test/executable/ExecutableRefTest.java @@ -2,6 +2,7 @@ import org.junit.Assert; import org.junit.Test; +import spoon.Launcher; import spoon.reflect.code.CtAbstractInvocation; import spoon.reflect.code.CtBlock; import spoon.reflect.code.CtConstructorCall; @@ -12,12 +13,16 @@ import spoon.reflect.declaration.CtMethod; import spoon.reflect.factory.Factory; import spoon.reflect.reference.CtExecutableReference; +import spoon.reflect.visitor.filter.TypeFilter; import spoon.test.TestUtils; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.List; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + public class ExecutableRefTest { @Test @@ -31,7 +36,7 @@ public void methodTest() throws Exception { Method method = executableReference.getActualMethod(); Assert.assertNotNull(method); - Assert.assertEquals("Hello World", + assertEquals("Hello World", method.invoke(null, ((CtLiteral) ctAbstractInvocation.getArguments().get(0)).getValue())); } @@ -46,7 +51,7 @@ public void constructorTest() throws Exception { Constructor constructor = executableReference.getActualConstructor(); Assert.assertNotNull(constructor); - Assert.assertEquals("Hello World", + assertEquals("Hello World", constructor.newInstance(((CtLiteral) ctAbstractInvocation.getArguments().get(0)).getValue())); } @@ -58,8 +63,25 @@ public void testGetActualClassTest() throws Exception { CtExecutableReference ref = method.getReference(); Method m = ref.getActualMethod(); - Assert.assertEquals("myMethod", m.getName()); - Assert.assertEquals(0, m.getExceptionTypes().length); + assertEquals("myMethod", m.getName()); + assertEquals(0, m.getExceptionTypes().length); + } + + @Test + public void testSameTypeInConstructorCallBetweenItsObjectAndItsExecutable() { + final Launcher launcher = new Launcher(); + launcher.getEnvironment().setNoClasspath(true); + launcher.addInputResource("./src/test/resources/executable/CmiContext_1.2.java"); + launcher.setSourceOutputDirectory("./target/executable"); + launcher.run(); + + final CtClass aClass = launcher.getFactory().Class().get("org.objectweb.carol.jndi.spi.CmiContext"); + final List ctConstructorCalls = aClass.getElements(new TypeFilter<>(CtConstructorCall.class)); + + for (CtConstructorCall constructorCall : ctConstructorCalls) { + assertNotNull(constructorCall.getExecutable()); + assertEquals(constructorCall.getExecutable().getType(), constructorCall.getType()); + } } private CtAbstractInvocation getInvocationFromMethod(String methodName) throws Exception { @@ -69,14 +91,14 @@ private CtAbstractInvocation getInvocationFromMethod(String methodName) throw Assert.assertNotNull(clazz); List> methods = clazz.getMethodsByName(methodName); - Assert.assertEquals(1, methods.size()); + assertEquals(1, methods.size()); CtMethod ctMethod = methods.get(0); CtBlock ctBody = (CtBlock) ctMethod.getBody(); Assert.assertNotNull(ctBody); List ctStatements = ctBody.getStatements(); - Assert.assertEquals(1, ctStatements.size()); + assertEquals(1, ctStatements.size()); CtStatement ctStatement = ctStatements.get(0); Assert.assertTrue(ctStatement instanceof CtAbstractInvocation); diff --git a/src/test/resources/executable/CmiContext_1.2.java b/src/test/resources/executable/CmiContext_1.2.java new file mode 100644 index 00000000000..e70a199450a --- /dev/null +++ b/src/test/resources/executable/CmiContext_1.2.java @@ -0,0 +1,118 @@ +/** + * Copyright (C) 2002-2006 - INRIA (www.inria.fr) + * + * CAROL: Common Architecture for RMI ObjectWeb Layer + * + * This library is developed inside the ObjectWeb Consortium, + * http://www.objectweb.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * -------------------------------------------------------------------------- + * $Id: CmiContext.java,v 1.2 2006-01-26 16:28:55 pelletib Exp $ + * -------------------------------------------------------------------------- + */ +package org.objectweb.carol.jndi.spi; + +import java.io.Serializable; +import java.rmi.Remote; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.Referenceable; +import javax.rmi.CORBA.PortableRemoteObjectDelegate; + +import org.objectweb.carol.jndi.wrapping.JNDIResourceWrapper; +import org.objectweb.carol.jndi.wrapping.UnicastJNDIReferenceWrapper; +import org.objectweb.carol.rmi.exception.NamingExceptionHelper; +import org.objectweb.carol.util.configuration.ConfigurationRepository; + +/** + * @author Florent Benoit + * @author Benoit Pelletier + */ +public class CmiContext extends AbsContext implements Context { + + /** + * Constructs an CMI Wrapper context + * @param cmiContext the inital CMI context + */ + public CmiContext(Context cmiContext) { + super(cmiContext); + } + + + /** + * If this object is a reference wrapper return the reference If this object + * is a resource wrapper return the resource + * @param o the object to resolve + * @param name name of the object to unwrap + * @return the unwrapped object + * @throws NamingException if the object cannot be unwraped + */ + protected Object unwrapObject(Object o, Name name) throws NamingException { + return super.defaultUnwrapObject(o, name); + } + + /** + * Wrap an Object : If the object is a reference wrap it into a Reference + * Wrapper Object here the good way is to contact the carol configuration to + * get the portable remote object + * @param o the object to encode + * @param name of the object + * @param replace if the object need to be replaced + * @return a Remote JNDIRemoteReference Object if o is a + * resource o if else + * @throws NamingException if object cannot be wrapped + */ + protected Object wrapObject(Object o, Name name, boolean replace) throws NamingException { + try { + // Add wrapper for the two first cases. Then it will use PortableRemoteObject instead of UnicastRemoteObject + // and when fixing JRMP exported objects port, it use JRMPProdelegate which is OK. + if ((!(o instanceof Remote)) && (o instanceof Referenceable)) { + return new UnicastJNDIReferenceWrapper(((Referenceable) o).getReference(), getObjectPort()); + } else if ((!(o instanceof Remote)) && (o instanceof Reference)) { + return new UnicastJNDIReferenceWrapper((Reference) o, getObjectPort()); + } else if ((!(o instanceof Remote)) && (!(o instanceof Referenceable)) && (!(o instanceof Reference)) + && (o instanceof Serializable)) { + // Only Serializable (not implementing Remote or Referenceable or + // Reference) + JNDIResourceWrapper irw = new JNDIResourceWrapper((Serializable) o); + PortableRemoteObjectDelegate proDelegate = ConfigurationRepository.getCurrentConfiguration().getProtocol().getPortableRemoteObject(); + proDelegate.exportObject(irw); + + Remote oldObj = (Remote) addToExported(name, irw); + if (oldObj != null) { + if (replace) { + proDelegate.unexportObject(oldObj); + } else { + proDelegate.unexportObject(irw); + addToExported(name, oldObj); + throw new NamingException("Object '" + o + "' with name '" + name + "' is already bind"); + } + } + return irw; + } else { + return o; + } + } catch (Exception e) { + throw NamingExceptionHelper.create("Cannot wrap object '" + o + "' with name '" + name + "' : " + + e.getMessage(), e); + } + } +} From 8a0927b15a646902eddd418c976b48213ad5fd1e Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Fri, 20 Nov 2015 14:33:02 +0100 Subject: [PATCH 2/2] refactor: Use get/setType methods in executable in CtNewClass. In CtNewClass#getType(), we use getExecutable().getType. In CtNewClass#setType(), we throw an UnsupportedOperationException. --- .../support/compiler/jdt/JDTTreeBuilder.java | 48 ++++++++++--------- .../reflect/code/CtConstructorCallImpl.java | 11 +++++ .../test/executable/ExecutableRefTest.java | 3 +- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java index f976dda4c36..c5393301bb8 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java @@ -316,10 +316,14 @@ void enter(CtElement e, ASTNode node) { ((CtStatement) current).setLabel(context.label.pop()); } - if (e instanceof CtTypedElement && node instanceof Expression) { - if (((CtTypedElement) e).getType() == null && !(e instanceof CtInvocation)) { - ((CtTypedElement) e).setType(references.getTypeReference(((Expression) node).resolvedType)); + try { + if (e instanceof CtTypedElement && node instanceof Expression) { + if (((CtTypedElement) e).getType() == null) { + ((CtTypedElement) e).setType(references.getTypeReference(((Expression) node).resolvedType)); + } } + } catch (UnsupportedOperationException ignore) { + // For some element, we throw an UnsupportedOperationException when we call setType(). } } @@ -1654,6 +1658,22 @@ public boolean visit(AllocationExpression allocationExpression, BlockScope scope } private > T buildCommonPartForCtNewClassAndCtConstructorCall(AllocationExpression allocationExpression, BlockScope scope, T constructorCall) { + if (allocationExpression.binding != null) { + constructorCall.setExecutable(references.getExecutableReference(allocationExpression.binding)); + } else { + final CtExecutableReference ref = factory.Core().createExecutableReference(); + ref.setSimpleName(CtExecutableReference.CONSTRUCTOR_NAME); + ref.setType(references.getTypeReference(null, allocationExpression.type)); + ref.setDeclaringType(references.getTypeReference(null, allocationExpression.type)); + + final List> parameters = new ArrayList>(allocationExpression.argumentTypes.length); + for (TypeBinding b : allocationExpression.argumentTypes) { + parameters.add(references.getTypeReference(b)); + } + ref.setParameters(parameters); + constructorCall.setExecutable(ref); + } + if (allocationExpression.type != null) { final TypeReference[][] typeArguments = allocationExpression.type.getTypeArguments(); // If typeArguments are null or empty, we have an element with a generic type. @@ -1668,28 +1688,10 @@ private > T buildCommonPartForCtNewClassAndC } } } - constructorCall.setType(references.getTypeReference(allocationExpression.type.resolvedType)); + constructorCall.getExecutable().setType(references.getTypeReference(allocationExpression.type.resolvedType)); context.isGenericTypeExplicit = true; } else if (allocationExpression.expectedType() != null) { - constructorCall.setType(references.getTypeReference(allocationExpression.expectedType())); - } - if (allocationExpression.binding != null) { - constructorCall.setExecutable(references.getExecutableReference(allocationExpression.binding)); - } else { - final CtExecutableReference ref = factory.Core().createExecutableReference(); - ref.setSimpleName(CtExecutableReference.CONSTRUCTOR_NAME); - ref.setType(references.getTypeReference(null, allocationExpression.type)); - ref.setDeclaringType(references.getTypeReference(null, allocationExpression.type)); - - final List> parameters = new ArrayList>(allocationExpression.argumentTypes.length); - for (TypeBinding b : allocationExpression.argumentTypes) { - parameters.add(references.getTypeReference(b)); - } - ref.setParameters(parameters); - constructorCall.setExecutable(ref); - } - if (constructorCall.getExecutable() != null) { - constructorCall.getExecutable().setType(constructorCall.getType()); + constructorCall.getExecutable().setType(references.getTypeReference(allocationExpression.expectedType())); } if (allocationExpression.genericTypeArguments() != null) { diff --git a/src/main/java/spoon/support/reflect/code/CtConstructorCallImpl.java b/src/main/java/spoon/support/reflect/code/CtConstructorCallImpl.java index a348c7269d8..3030f6e9d8d 100644 --- a/src/main/java/spoon/support/reflect/code/CtConstructorCallImpl.java +++ b/src/main/java/spoon/support/reflect/code/CtConstructorCallImpl.java @@ -6,6 +6,7 @@ import spoon.reflect.code.CtStatement; import spoon.reflect.code.CtStatementList; import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtTypedElement; import spoon.reflect.reference.CtExecutableReference; import spoon.reflect.reference.CtGenericElementReference; import spoon.reflect.reference.CtTypeReference; @@ -152,4 +153,14 @@ public boolean removeActualTypeArgument(CtTypeReference actualTypeArgument) { return actualTypeArguments != CtElementImpl.>emptyList() && actualTypeArguments.remove(actualTypeArgument); } + + @Override + public CtTypeReference getType() { + return getExecutable() == null ? null : getExecutable().getType(); + } + + @Override + public C setType(CtTypeReference type) { + throw new UnsupportedOperationException("Uses getExecutable().setType(CtTypeReference)"); + } } diff --git a/src/test/java/spoon/test/executable/ExecutableRefTest.java b/src/test/java/spoon/test/executable/ExecutableRefTest.java index fe1dde1f4c3..bd2e6f4e97b 100644 --- a/src/test/java/spoon/test/executable/ExecutableRefTest.java +++ b/src/test/java/spoon/test/executable/ExecutableRefTest.java @@ -80,8 +80,9 @@ public void testSameTypeInConstructorCallBetweenItsObjectAndItsExecutable() { for (CtConstructorCall constructorCall : ctConstructorCalls) { assertNotNull(constructorCall.getExecutable()); - assertEquals(constructorCall.getExecutable().getType(), constructorCall.getType()); } + + TestUtils.canBeBuilt("./target/executable", 8, true); } private CtAbstractInvocation getInvocationFromMethod(String methodName) throws Exception {