I'm running Mwe2 workflow programmatically and I need to add referencedResource for the Terminals.xtext to the GenerateYourDsl.mwe2 file in order to run this workflow successfully. Mentioned GenerateYourDsl.mwe2 file is generated by Xtext when I create new project - I didn't modify it.
Is it somehow possible to get object out of this workflow, access it in Java and add this one attribute to the language attribute of the component attribute of the workflow ?
Here's the workflow:
Workflow {
component = XtextGenerator {
configuration = {
project = StandardProjectConfig {
baseName = "org.example.yourdsl"
rootPath = rootPath
eclipsePlugin = {
enabled = true
}
createEclipseMetaData = true
}
code = {
encoding = "UTF-8"
lineDelimiter = "\n"
fileHeader = "/*\n * generated by Xtext \${version}\n */"
}
}
language = StandardLanguage {
name = "org.example.yourdsl.YourDsl"
fileExtensions = "yourdsl"
//following line needs to be added - in original generated workflow it is not
referencedResource = "platform:/resource/org.eclipse.xtext/org/eclipse/xtext/common/Terminals.xtext"
serializer = {
generateStub = false
}
validator = {
// composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
// Generates checks for #Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage
generateDeprecationValidation = true
}
}
}
}
I'm generating projects programmatically (using CliProjectsCreator and WizardConfiguration) and need to run the workflow when the projects are generated in order to generate src, src-gen files etc. But as I'm trying to run it programmatically (not in Eclipse) and Terminals are used in my grammar, I'm getting this error:
XtextLinkingDiagnostic: null:1 Couldn't resolve reference to Grammar 'org.eclipse.xtext.common.Terminals'.
TransformationDiagnostic: null:36 Cannot create datatype WS. If this is supposed to return EString, make sure you have imported 'http://www.eclipse.org/emf/2002/Ecore' (ErrorCode: NoSuchTypeAvailable)
TransformationDiagnostic: null:39 Cannot create datatype NAME_TERMINAL. If this is supposed to return EString, make sure you have imported 'http://www.eclipse.org/emf/2002/Ecore' (ErrorCode: NoSuchTypeAvailable)
TransformationDiagnostic: null:42 Cannot create datatype VALUE_TERMINAL. If this is supposed to return EString, make sure you have imported 'http://www.eclipse.org/emf/2002/Ecore' (ErrorCode: NoSuchTypeAvailable)
there should be no need to add the terminals grammar explicitely. It should be found on the classpath via org.eclipse.xtext.resource.ClassloaderClasspathUriResolver.resolve(Object, URI) if the workflow is called with a proper classpath.
have a look what the wizard creates when selecting maven: a call to the maven exec plugin calling into Mwe2Launcher main with the proper classpath
Related
I have some files that I need to copy to a directory configured in the .cfg file as part of installing the bundle in Karaf server. I couldn't figure out what exactly is the js method to invoke. Below id the snippet I used to extract a jar using postProcess in metatype.js, but how do I copy a file..
var postProcess = function(group, map ) {
if(map["destination.script.path"] && map["destination.script.path"].trim()!='') {
scope.installTasks.expandResources(java.lang.System.getProperty('karaf.base') +"/data/hrc/install/source/resources.jar",map["destination.script.path"]+"/scripts",false,
function(key,success) {
print("expanded " + success);
},
function(key,fail){
print(fail.getMessage());
});
}
};
var success = function(source,val){
//print(val);
}
var fail = function(source,e){
//print(source);
}
This is how my OSGI-INF looks like
Sorry, installTasks is an internal utility used in my project.
I wrote some code to replace variables in docx tamplate file header.
List<SectionWrapper> sectionWrappers = this.wordMLPackage.getDocumentModel().getSections();
for (SectionWrapper sw : sectionWrappers) {
HeaderFooterPolicy hfp = sw.getHeaderFooterPolicy();
HeaderPart defaultHP = hfp.getDefaultHeader();
if (defaultHP != null) {
defaultHP.variableReplace(getVariablesForChange());
if (hfp.getFirstHeader() != null) {
hfp.getFirstHeader().variableReplace(getVariablesForChange());
}
}
}
getVariablesForChange() is a Map has contains the variables and values.
When I running the unit test the replace is corectly fine but I use this in my web application on Tomee Plume the variables does not replaced.
For example the variable is: ${TOCHANGE} it looks like this after change TOCHANGE.
Docx4j version is: 3.3.6
Please help me to resolve this issue.
It won't work if your KEY is split across separate runs in your docx.
See https://github.com/plutext/docx4j/blob/master/src/main/java/org/docx4j/model/datastorage/migration/VariablePrepare.java
This is a complicated question but I will do my best to describe my problem.
I need to load 2 versions of the same JAR in a top level class (v1.jar and v2.jar) so I have access to both versions of the jar. The reason for this is because I want to test if any feature in v2.jar has regressed from v1.jar
In my top level class, I want to call methods of v1.jar and v2.jar and then validate the output from v1 against v2 output. This way I can be certain nothing got screwed up.
class Common {
// Names of the classes would be the same so not sure how I would invoke the classes from the 2 different jars?
String resultv1 = EngineV1.run("a","b","c");
String resultv2 = EngineV2.run("a","b","c");
Assert.equals(resultv1, resultv2, "Regression has been introduced...");
}
I can't import v1 and v2 jars as maven dependencies since this will create a version conflict in maven and by default maven will use the newest jar. So I thought about creating a common interface and having 2 different implementation classes of that interface. Then in the toplevel I can use class loaders to load v1 and v2 jars, etc. But this way not work since I would have to change production v1.jar to implement the common interface.
Any help or insight will be much appreciated. I'd very much like to see samples if possible. And please don't refer me to other threads
Your test class can set up a ClassLoader for each .jar file. The easiest way to do that, is to use URLClassLoader.
Example:
File jar1 = new File("/path/to/v1.jar");
File jar2 = new File("/path/to/v2.jar");
URLClassLoader v1Loader = URLClassLoader.newInstance(new URL[] { jar1.toURI().toURL() });
URLClassLoader v2Loader = URLClassLoader.newInstance(new URL[] { jar2.toURI().toURL() });
Class<?> engineClass1 = v1Loader.loadClass("org.example.Engine");
Class<?> engineClass2 = v2Loader.loadClass("org.example.Engine");
Method runMethod1 = engineClass1.getMethod("run");
Method runMethod2 = engineClass2.getMethod("run");
Object engine1 = engineClass1.newInstance();
Object engine2 = engineClass2.newInstance();
String result1 = (String) runMethod1.invoke(engine1);
String result2 = (String) runMethod2.invoke(engine2);
Note that since neither .jar file is on the classpath of the test code, the code cannot declare any variables of types from the .jar files. All access from test code must be done using reflection.
UPDATE
You might also need to change the context class loader when making the calls:
String result1, result2;
Thread thread = Thread.currentThread();
ClassLoader myLoader = thread.getContextClassLoader();
try {
thread.setContextClassLoader(v1Loader);
result1 = (String) runMethod1.invoke(engine1);
thread.setContextClassLoader(v2Loader);
result2 = (String) runMethod2.invoke(engine2);
} finally {
thread.setContextClassLoader(myLoader);
}
// Compare result1 and result2
I found this from a different Stackoverflow question where I needed to load a jar during runtime
/*
* Adds the supplied Java Archive library to java.class.path. This is benign
* if the library is already loaded.
*/
public static synchronized void loadLibrary(java.io.File jar) throws Exception {
try {
/*We are using reflection here to circumvent encapsulation; addURL is not public*/
java.net.URLClassLoader loader = (java.net.URLClassLoader)ClassLoader.getSystemClassLoader();
java.net.URL url = jar.toURI().toURL();
/*Disallow if already loaded*/
for (java.net.URL it : java.util.Arrays.asList(loader.getURLs())){
if (it.equals(url)){
return;
}
}
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(loader, new Object[]{url});
} catch (final java.lang.NoSuchMethodException |
java.lang.IllegalAccessException |
java.net.MalformedURLException |
java.lang.reflect.InvocationTargetException e){
throw new Exception(e);
}
}
Works for my purposes
I have a simple annotation processor that needs to read a configuration file from the same project as the annotated classes. Example structure:
- myproject
- src
- main
- java
- my.package.SourceFile
- resources
- config.json
In the annotation processor, I try to read the file:
FileObject resource = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", "config.json");
but it throws FileNotFoundException. I also tried other paths, such as ../resources/config.json, (which throws Invalid relative name: ../resources/config.json). And I tried putting the config file in src/main/java (and even src/main/java/my/package) instead, which I don't like, but that also still throws FileNotFoundException.
It would already help if I could get filer.getResource() to tell me where it's looking. To find that out, I tried generating a file:
filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "dummy");
which generated in myproject/build/classes/main/dummy. Unfortunately, I can't generate in SOURCE_PATH, so that doesn't help with finding this out.
I'd expect that the stuff from src/main/resources gets copied to target/classes during the build (prior to annotation processing). In that case you can open them like this:
ProcessingEnvironment pe = ...;
FileObject fileObject = pe.getFiler()
.getResource( StandardLocation.CLASS_OUTPUT, "", "config.json" );
InputStream jsonStream = fileObject.openInputStream();
I've looked at this with one of the Project Lombok developers. If anyone knows annotation processing, it's them ;)
Our conclusion was, that the JavacFileManager that handles the request internally, does not have a path to resolve StandardLocation.SOURCE_PATH to. We're not sure, but it might be related to building with Gradle.
I had the same problem and was searching for solution for a while and found this cool hack that does the trick for Android
And below you can see my solution from pure Java/Kotlin project
fun ProcessingEnvironment.getResourcesDirectory(): File {
val dummySourceFile = filer.createSourceFile("dummy" + System.currentTimeMillis())
var dummySourceFilePath = dummySourceFile.toUri().toString()
if (dummySourceFilePath.startsWith("file:")) {
if (!dummySourceFilePath.startsWith("file://")) {
dummySourceFilePath = "file://" + dummySourceFilePath.substring("file:".length)
}
} else {
dummySourceFilePath = "file://$dummySourceFilePath"
}
val cleanURI = URI(dummySourceFilePath)
val dummyFile = File(cleanURI)
val projectRoot = dummyFile.parentFile.parentFile.parentFile.parentFile.parentFile
return File(projectRoot.absolutePath + "/resources")
}
Following function works for me with annotation processor being triggered by gradle, it's not the pretties one but works:
private fun resolveApplicationPropertiesFile(): File {
val projectRoot = Path.of(processingEnv.filer.getResource(StandardLocation.CLASS_OUTPUT, "", "doesntmatter")
.toUri())
.parent
.parent
.parent
.parent
.parent
.parent
val properties = Path.of(projectRoot.toString(), "src", "main", "resources", "application.yml")
return properties.toFile()
}
where processingEnv is a member of AbstractProcessor
If your element is instance of TypeElement,then you can use these code to find your source code
FileObject fileObject = processingEnv.getFiler().getResource(
StandardLocation.SOURCE_PATH, element.getEnclosingElement().toString(),
element.getSimpleName() + ".java");
element.getEnclosingElement() is your class package, eg: com.fool
element.getSimpleName() is your class name, eg: Person
then you can print them:
CharSequence content = fileObject.getCharContent(true);
I'm writing Intellij IDEA plugin for my project, and I've faced a problem - I cannot get some ingo about method (PsiMethod) from my code.
First, I want to know is this method public.
And second, I want to get fully-qualified names of the parameter classes. Currently I'm doing it like this:
method.getReturnTypeNoResolve().getInternalCanonicalText()
But it doesn't provide full name (with package name) for the standard JVM classes like String and List.
UPDATE First problem solved with the following code:
PsiUtil.getAccessLevel(method.getModifierList()) == PsiUtil.ACCESS_LEVEL_PUBLIC
But I still cannot get fully qualified class name
UPDATE 2 Here is the full listing of my code:
Project currentProject = DataKeys.PROJECT.getData(e.getDataContext());
PsiClass abstractComponentClass = JavaPsiFacade.getInstance(currentProject).findClass("com.mjolnirr.lib.component.AbstractComponent", GlobalSearchScope.allScope(currentProject));
TreeClassChooser result = TreeClassChooserFactory
.getInstance(currentProject)
.createInheritanceClassChooser("Choose the class to generate manifest",
GlobalSearchScope.projectScope(currentProject),
abstractComponentClass,
false,
false,
null);
result.showDialog();
PsiClass classToGenerate = result.getSelected();
List<ManifestMethod> methods = new ArrayList<ManifestMethod>();
for (PsiMethod method : classToGenerate.getAllMethods()) {
// If this method is inherited from the Object class we don't need it
if (isComponentInitialize(method)) {
continue;
}
List<ManifestParameter> parameters = new ArrayList<ManifestParameter>();
for (PsiParameter param : method.getParameterList().getParameters()) {
parameters.add(new ManifestParameter(param.getType().getCanonicalText().replaceAll("\\<.*?\\>", "")));
}
if (method.getReturnType() != null) {
ManifestMethod manifestMethod = new ManifestMethod(method.getName(),
method.getReturnTypeNoResolve().getInternalCanonicalText().replaceAll("\\<.*?\\>", ""),
parameters);
if (!methods.contains(manifestMethod) && isPublic(method)) {
System.out.println("->" + method.getReturnType().getCanonicalText());
methods.add(manifestMethod);
}
}
}
Solved - my test IDEA instance has wrong Java SDK connected.