Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Unit testing using CompilationTestHelper(Non-class file cannot be found when executing method trying to read that file.)
Unit testing using CompilationTestHelper [message #1741877] Tue, 30 August 2016 11:17 Go to next message
Marek Stankiewicz is currently offline Marek StankiewiczFriend
Messages: 11
Registered: June 2016
Junior Member
Hi, I am using CompilationTestHelper to unit test generated Java code. Compilation works fine, but I having some configuration problems during execution when generated code has the following sequence:

URL url = ShowPerson.class.getResource("ShowPerson.xsd");
InputStream inputStream = url.openStream();
List<SDOType> list = XSDHelper.INSTANCE.define(inputStream, url.toString());

File ShowPerson.xsd is also generated and located in the correct place when running outside unit test. It seams that generated file is not on class path when trying run generated and compiled class during unit test. I guess I need to do something with the configuration. Any help appreciated.

Re: Unit testing using CompilationTestHelper [message #1741880 is a reply to message #1741877] Tue, 30 August 2016 11:37 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
can you be more specific what you are doing in your test code?

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Unit testing using CompilationTestHelper [message #1741884 is a reply to message #1741880] Tue, 30 August 2016 11:55 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
you may consider customizing org.eclipse.xtext.xbase.compiler.InMemoryJavaCompiler.Result.getClassLoader()

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Unit testing using CompilationTestHelper [message #1741890 is a reply to message #1741884] Tue, 30 August 2016 13:08 Go to previous messageGo to next message
Marek Stankiewicz is currently offline Marek StankiewiczFriend
Messages: 11
Registered: June 2016
Junior Member
This is snapshot of the test method:
        @Inject extension ReflectExtensions
	@Inject extension CompilationTestHelper
	@Inject public TemporaryFolder temporaryFolder
	@Test def void testMoveStatment() {
		'''
			package example.one
					import commonj.sdo.DataObject
					import commonj.sdo.helper.DataFactory
					import commonj.sdo.helper.XSDHelper
					import org.eclipse.persistence.sdo.SDOType 
			jg-sys MySystem
			
			jg-entity Person {
				  jg-attr number : int
				  jg-attr name : String
			}
			
				jg-action ShowPerson {
				   jg-imports {
					jg-view imp jg-entity Person {
						number, name
					}
				}
				   jg-exports {
					jg-view exp jg-entity Person {
						number, name
					}
				}
				jg-main {

				}
			
		'''.compile [
			
			allGeneratedResources.forEach[p1, p2|
				println(p2)
			]
						 		
			getCompiledClass("example.one.ShowPerson").newInstance => [				
				it.invoke("entry")
			]
		]
	}


All required code is generated correctly including xsd file.

<?xml version="1.0" encoding="UTF-8"?>
   <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
		xmlns="http://example.com/IPO" targetNamespace="http://example.com/IPO">
<xsd:element name="imp" type="Imp" />  
<xsd:complexType name="Imp">  
<xsd:attribute name="number" type="xsd:int" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>  
<xsd:element name="exp" type="Exp" />  
<xsd:complexType name="Exp">  
<xsd:attribute name="number" type="xsd:int" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>  
</xsd:schema>  


package example.one;

import commonj.sdo.DataObject;
import commonj.sdo.helper.DataFactory;
import commonj.sdo.helper.XSDHelper;
import eu.jgen.gen.open.mdl.lib.IllegalRuntimeOperation;
import eu.jgen.gen.open.mdl.lib.JXActionBlock;
import eu.jgen.gen.open.mdl.lib.JXSimpleView;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import org.eclipse.persistence.sdo.SDOType;

@SuppressWarnings("all")
public class ShowPerson extends JXActionBlock {
  private DataObject sdo;
  
  private SDOType impType;
  
  private SDOType expType;
  
  public class Imp extends JXSimpleView {
    public final static int START_PROPERTY_INDEX = 0;
    
    public final static int END_PROPERTY_INDEX = START_PROPERTY_INDEX + 1;
    
    public Imp(final DataObject sdo) {
      super(sdo);
    }
    
    public void setNumber(final int value) {
      get_sdo().set(START_PROPERTY_INDEX + 0, value);
    }
    
    public int getNumber() {
      return get_sdo().getInt(START_PROPERTY_INDEX + 0);
    }
    
    public void setName(final String value) {
      get_sdo().set(START_PROPERTY_INDEX + 1, value);
    }
    
    public String getName() {
      return get_sdo().getString(START_PROPERTY_INDEX + 1);
    }
  }
  
  public ShowPerson.Imp imp = null;
  
  public class Exp extends JXSimpleView {
    public final static int START_PROPERTY_INDEX = 0;
    
    public final static int END_PROPERTY_INDEX = START_PROPERTY_INDEX + 1;
    
    public Exp(final DataObject sdo) {
      super(sdo);
    }
    
    public void setNumber(final int value) {
      get_sdo().set(START_PROPERTY_INDEX + 0, value);
    }
    
    public int getNumber() {
      return get_sdo().getInt(START_PROPERTY_INDEX + 0);
    }
    
    public void setName(final String value) {
      get_sdo().set(START_PROPERTY_INDEX + 1, value);
    }
    
    public String getName() {
      return get_sdo().getString(START_PROPERTY_INDEX + 1);
    }
  }
  
  public ShowPerson.Exp exp = null;
  
  public ShowPerson() {
    try {
    	URL url = ShowPerson.class.getResource("ShowPerson.xsd");
    	InputStream inputStream = url.openStream();
    	List<SDOType> list = XSDHelper.INSTANCE.define(inputStream, url.toString());
    impType = findSDOType(list, "Imp");
    imp = new ShowPerson.Imp(DataFactory.INSTANCE.create(impType));
    expType = findSDOType(list, "Exp");
    exp = new ShowPerson.Exp(DataFactory.INSTANCE.create(expType));
    } catch (Exception e) {
    	throw new IllegalRuntimeOperation("ShowPerson: Cannot define SDO types");		 
    }
  }
  
  public void entry() {
  }
}



Test stops with
eu.jgen.gen.open.mdl.lib.IllegalRuntimeOperation: ShowPerson: Cannot define SDO types
at example.one.ShowPerson.<init>(ShowPerson.java:88)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
.....

I am sure it fails on 'InputStream inputStream = url.openStream();'

Thanks for looking into the problem.
Re: Unit testing using CompilationTestHelper [message #1741891 is a reply to message #1741890] Tue, 30 August 2016 13:10 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
yes that is how that special class loader works. i assume it doesnt know anything about the xsd

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Unit testing using CompilationTestHelper [message #1741935 is a reply to message #1741891] Tue, 30 August 2016 16:44 Go to previous message
Marek Stankiewicz is currently offline Marek StankiewiczFriend
Messages: 11
Registered: June 2016
Junior Member
I followed your advice and here is modified InMemoryJavaCompiler so can load non-java text files. It works for me.

Thanks
Regards

package eu.jgen.gen.open.mdl.tests

import java.io.ByteArrayInputStream
import java.io.InputStream
import java.net.URL
import java.net.URLConnection
import java.util.HashMap
import java.util.Map
import java.util.Set
import org.eclipse.jdt.core.compiler.CategorizedProblem
import org.eclipse.jdt.internal.compiler.Compiler
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies
import org.eclipse.jdt.internal.compiler.batch.CompilationUnit
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit
import org.eclipse.jdt.internal.compiler.env.INameEnvironment
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend.lib.annotations.Data
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
import org.eclipse.xtext.util.JavaVersion
import eu.jgen.gen.open.mdl.tests.InMemoryJavaCompiler2.Result

class InMemoryJavaCompiler2 {

	@FinalFieldsConstructor private static class ClassLoaderBasedNameEnvironment implements INameEnvironment {

		val ClassLoader classLoader

		Map<String, NameEnvironmentAnswer> cache = newHashMap()

		override cleanup() {
			cache.clear
		}

		override findType(char[][] compoundTypeName) {
			val fileName = compoundTypeName.map[String.valueOf(it)].join("/") + ".class"
			if (cache.containsKey(fileName)) {
				return cache.get(fileName)
			}
			val url = classLoader.getResource(fileName)
			if (url == null) {
				cache.put(fileName, null)
				return null;
			}
			val reader = ClassFileReader.read(url.openStream, fileName)
			val result = new NameEnvironmentAnswer(reader, null)
			cache.put(fileName, result)
			return result
		}

		override findType(char[] typeName, char[][] packageName) {
			val fileName = packageName.map[String.valueOf(it)].join("/") + "/" + String.valueOf(typeName) + ".class"
			if (cache.containsKey(fileName)) {
				return cache.get(fileName)
			}
			val url = classLoader.getResource(fileName)
			if (url == null) {
				cache.put(fileName, null)
				return null;
			}
			val reader = ClassFileReader.read(url.openStream, fileName)
			val result = new NameEnvironmentAnswer(reader, null)
			cache.put(fileName, result)
			return result
		}

		override isPackage(char[][] parentPackageName, char[] packageName) {
			// Working hack
			return Character.isLowerCase(packageName.head)
		}
	}

	static package class ByteClassLoader extends ClassLoader {
		Map<String, byte[]> classMap
		JavaSource[] sources

		new(Map<String, byte[]> classMap, ClassLoader parent, JavaSource[] sources) {
			super(parent)
			this.classMap = classMap
			this.sources = sources
		}

		override protected Class<?> findClass(String name) throws ClassNotFoundException {
			var byte[] bytes = classMap.get(name)
			if (bytes === null) {
				return super.findClass(name)
			} else {
				return defineClass(name, bytes, 0, bytes.length)
			}
		}

		override protected findResource(String path) {
			if (path.endsWith(".class")) {
				val className = path.substring(0, path.length - 6).replace("/", ".")
				val bytes = classMap.get(className)
				if (bytes != null) {
					return new URL("in-memory", null, -1, path, [
						new URLConnection(it) {
							override void connect() {}

							override InputStream getInputStream() {
								return new ByteArrayInputStream(bytes)
							}
						}
					])
				}
			} else if (!path.endsWith(".class")) {
				val source = sources.findFirst [ source |
					source.fileName.endsWith(path)
				]
				if (source != null) {
					val bytes = source.code.bytes
					if (bytes != null) {
						return new URL("in-memory", null, -1, path, [
							new URLConnection(it) {
								override void connect() {}
								override InputStream getInputStream() {
									return new ByteArrayInputStream(bytes)
								}
							}
						])
					}
				}
			}
			return null
		}
	}

	val INameEnvironment nameEnv
	val ClassLoader parentClassLoader
	val CompilerOptions compilerOptions

	new(ClassLoader parent, JavaVersion javaVersion) {
		nameEnv = new ClassLoaderBasedNameEnvironment(parent)
		parentClassLoader = parent
		compilerOptions = new CompilerOptions
		val classFmt = javaVersion.toClassFmt
		sourceLevel = classFmt
		complianceLevel = classFmt
		compilerOptions.targetJDK = classFmt
		compilerOptions.inlineJsrBytecode = true
		compilerOptions.preserveAllLocalVariables = true
	}

	new(ClassLoader parent, CompilerOptions compilerOptions) {
		nameEnv = new ClassLoaderBasedNameEnvironment(parent)
		parentClassLoader = parent
		this.compilerOptions = new CompilerOptions(compilerOptions.map)
	}

	private def long toClassFmt(JavaVersion version) {
		switch (version) {
			case JAVA5: return ClassFileConstants.JDK1_5
			case JAVA6: return ClassFileConstants.JDK1_6
			case JAVA7: return ClassFileConstants.JDK1_7
			case JAVA8: return ((ClassFileConstants.MAJOR_VERSION_1_7 + 1) << 16) + ClassFileConstants.MINOR_VERSION_0 // ClassFileConstants.JDK1_8
		}
	}

	/**
	 * sets the source level (see @link(org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants))
	 */
	private def void setSourceLevel(long jdkVersion) {
		compilerOptions.sourceLevel = jdkVersion
		// these fields have been introduces in JDT 3.7
		try {
			CompilerOptions.getField("originalSourceLevel").setLong(compilerOptions, jdkVersion)
		} catch (NoSuchFieldException e) {
			// ignore
		}
	}

	/**
	 * sets the compliance level (see @link(org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants))
	 */
	private def void setComplianceLevel(long jdkVersion) {
		compilerOptions.complianceLevel = jdkVersion
		// these fields have been introduces in JDT 3.7
		try {
			CompilerOptions.getField("originalComplianceLevel").setLong(compilerOptions, jdkVersion)
		} catch (NoSuchFieldException e) {
			// ignore
		}
	}

	def Result compile(JavaSource... sources) {
		
		val nonjavaSources = sources.filter[source |
				!source.fileName.endsWith(".java")
			]

		val Result result = new Result(parentClassLoader, nonjavaSources)
		var compiler = new Compiler(nameEnv, DefaultErrorHandlingPolicies.proceedWithAllProblems(), compilerOptions, [
			for (cf : it.getClassFiles()) {
				val name = String.valueOf(cf.fileName)
				// println(name)
				result.classMap.put(cf.compoundName.map[String.valueOf(it)].join('.'), cf.bytes)
			}
		],
			new DefaultProblemFactory() {

				override createProblem(char[] originatingFileName, int problemId, String[] problemArguments,
					int elaborationId, String[] messageArguments, int severity, int startPosition, int endPosition,
					int lineNumber, int columnNumber) {
					val problem = super.createProblem(originatingFileName, problemId, problemArguments, elaborationId,
						messageArguments, severity, startPosition, endPosition, lineNumber, columnNumber)
					result.compilationProblems.add(problem)
					return problem
				}

				override createProblem(char[] originatingFileName, int problemId, String[] problemArguments,
					String[] messageArguments, int severity, int startPosition, int endPosition, int lineNumber,
					int columnNumber) {
						val problem = super.createProblem(originatingFileName, problemId, problemArguments,
							messageArguments, severity, startPosition, endPosition, lineNumber, columnNumber)
						result.compilationProblems.add(problem)
						return problem
					}

				})
				
			val javaSources = sources.filter[source |
				source.fileName.endsWith(".java")
			]

			var ICompilationUnit[] units = javaSources.map[new CompilationUnit(code.toCharArray(), fileName, null)]
			compiler.compile(units)
			return result
		}

		@FinalFieldsConstructor public static class Result {
			@Accessors val Set<CategorizedProblem> compilationProblems = newLinkedHashSet()
			val classMap = new HashMap<String, byte[]>
			val ClassLoader parentClassLoader
			val JavaSource[] sources

			def ClassLoader getClassLoader() {
				new ByteClassLoader(classMap, parentClassLoader, sources)
			}
		}

	}

	/**
	 * @since 2.9
	 */
	@Data class JavaSource {
		String fileName
		String code
	}


Previous Topic:Xtext grammar ambiguity problem
Next Topic:Xtext Gradle Dependancies
Goto Forum:
  


Current Time: Fri Apr 19 20:51:14 GMT 2024

Powered by FUDForum. Page generated in 0.04846 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top