Having problems while trying to execute an Acceleo module in standalone mode - java

I have successfully created an Acceleo module for M2T purposes and am trying to execute it from a Java program.
This is what I tried :
String[] str = {"/home/hamza/workspace/HLRedundancy/model/System1.xmi", "/home/hamza/workspace/HLRedundancy/"};
Generate.main(str);
Generate being the name of the Acceleo module I created and thus, the name of the Java class containing the Acceleo generation methods.
Here is the error I'm always getting :
Exception in thread "main" org.eclipse.acceleo.engine.AcceleoEvaluationException: The type of the first parameter of the main template named 'generateElement' is a proxy.
at org.eclipse.acceleo.engine.service.AcceleoService.doGenerate(AcceleoService.java:566)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.generate(AbstractAcceleoGenerator.java:193)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.doGenerate(AbstractAcceleoGenerator.java:158)
at HighLevelGenerator.main.Generate.doGenerate(Generate.java:250)
at HighLevelGenerator.main.Generate.main(Generate.java:160)
at Execute.main(Execute.java:11)
I've been searching for a while about this error but I have no idea about its cause.
Any idea about a solution to my problem ?
Thanks

The most common cause of this issue is failure in properly registering the metamodel and factory corresponding to your inpu model (System1.xmi).
If you look at the comments in the generated class "Generate.java", you will notice a number of places where we indicate steps to follow if running in standalone. The most important begin registerPackages where you are required to register your metamodel.
If you debug the launch down to the point where the model is loaded (place a breakpoint right after the line model = ModelUtils.load(newModelURI, modelResourceSet);), you can look at the model.eResource().getErrors() list to see whether there were errors loading your model.
You might also be interested in looking at this video describing the process (registration required) .

Check out the first line of your acceleo module,
what is the URI of the metamodel? Does it start with 'http://' ?
Maybe this can help:
Acceleo stand alone - first parameter is proxy

This issue happen when your meta model contains sub-packages and the top package not contain any class.
to solve the problem, add a Dummy class the the top package and regenerate the meta-model code. It worked fine for me.

Related

Obtaining the fully qualified name from an Annotation using Eclipse JDT AST

I am using the Eclipse JDT to build AST for Java source code, so I can do some code analysis. Currently I would like to obtain the fully qualified name of an annotation. Consider the code below:
import javax.persistence.Entity;
#Entity
public class Class1
If I visit this Compilation Unit, the #Entity is a MarkerAnnotation. And I can do some analysis on it. However I am unable to obtain the Fully qualified name. I would like to obtain "javax.persistence.Entiy". I have tried several ways, but with no success.
public boolean visit(MarkerAnnotation node) {
node.getTypeName(); //returns the simple name
node.getTypeName().getFullyQualifiedName();// I thought this would print javax.persistence.Entiy,
// but it only prints "Entity"
node.resolveTypeBinding().getName(); //Prints "Entity"
node.resolveTypeBinding().getBinaryName(); // Prints "Entity"
node.resolveAnnotationBinding().getName(); //Prints "Entity"
return super.visit(node);
}
I have also tried to cast MarkerAnnotation to Annotation, but I am still unable to get fully qualified name. During debugging sesssions, I had no success either navigating this node
I was able to get the fully qualified name using the imports() method of the CompilationUnit. I did some String manipulations on them, combining with the annotations simple name. However, I feel this is sort of hacky, and I need to look at every import, even ones that are not related to annotations.
What I would like is to obtain the fully qualified name directly from the node, i.e, from the MarkerAnnotation, NormalAnnotation and SingleMemberAnnotation. Is there any way to achieve this? What Am I missing here?
Thanks in advance!
From the javadoc of Annotation.resolveAnnotationBinding():
Note that bindings (which includes resolved annotations) are generally unavailable unless requested when the AST is being built.
So please check how you configure ASTParser, see ASTParser.setResolveBindings(boolean)

error: package generated.schema does not exist

In my Android Application I have an annotation processor which generates files using JavaPoet and places them under the package generated.schema.
The files are generating correctly. Whenever I use the generated file like so
GeneratedFile.someGeneratedMethod();
I get the following error:
error: package generated.schema does not exist.
But if I include the fully qualified class name instead of importing like so
generated.schema.GeneratedFile.someGeneratedMethod();
the code compiles and runs without any error.
I don't want to add complete package each time I am using GeneratedFile. I'm not sure what I did wrong, since I'm still learning to work with Annotation Processor.
Files generated by other libraries including Realm, DataBinding are all working correctly as expected.
File Generation :
using JavaPoet I run the following code.
if (roundEnvironment.processingOver()) {
for (TypeElement element : apiList) {
TypeSpec clazz = generateFile(element);
JavaFile.builder(NamespaceCreator.generateClassPackage(element), clazz)
.build()
.writeTo(filer);
}
}
NamespaceCreator.generateClassPackage(element) returns the package name for class i.e generated.schema.
While generating classes I was waiting for the last processing pass. the code generation encapsulated by
if (roundEnvironment.processingOver())
I was getting a warning because of this:
File for type 'generated.schema.GeneratedFile' created in the last round will not be subject to annotation processing.
I was aware of this warning before I posted the question, however I was willing to ignore further annotation processing on my generated files for simplicity of generating all files in one go.
Even though, after removing the last round/pass check from file generation I can correctly (with import) access the generated files without any error; I still don't understand how generating files throughout all rounds affects accessing files during build with import.
For that I will be posting a new question.

Passing a customized object to Scala template

I have an object profileModel in my profile package and my profile.scala.html file have following code
#(model: ProfileModel)
when I compiles, it is giving an error recursive value model needs type
But when I moved this class to models with my application.conf as
ebean.default="models.*"
it works.
My guess is scala compiler automatically adds models.* to class path at the time of compilation
Is there a way to make this work without moving the class back to models package ?
I am using play 2.2.1 built with Scala 2.10.2
If I understand you right, if your ProfileModel exists in profile package correct declaration in the view should be:
#(myProfile: profile.ProfileModel)
And 'yes', Play imports automatically all models and controllers (and also other well known types), but if you want to use any type in custom package (or ie. imported lib) you need to use full qualified path to it.

How can I get all #Entity classes from a Persistence Unit?

Problem
I'm writing a standalone utility program which, given a jar containing a JPA-2 annotated persistence unit, needs to programmatically get a list of all my #Entity classes in a particular persistence unit.
I'd like to decide which of 2 approaches would be the way to go to get this information, and why; or if there is another better way I haven't thought of.
Solution 1
Java program puts jar on the classpath, creates persistence unit from the classes in the jar using JavaSE methodologies. Then it uses the javax.persistence classes to get the JPA Metamodel, pull back list of class tokens from that.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MY_ PERSISTENCE_UNIT");
Metamodel mm = emf.getMetamodel();
// loop these, using getJavaType() from Type sub-interface to get
// Class tokens for managed classes.
mm.getManagedTypes();
Solution 2
Program scan the directories and files inside the specified jar for persistence.xml files, then finds one with the specified persistence unit name. Then XPath the file to get the list of <class> XML elements and read the fully qualified class names from there. From names, build class tokens.
Constraints/Concerns
I'd like to go with approach 1 if possible.
This utility will NOT run inside a container, but the jar is an EJB project designed to run inside one. How will this be a problem?
The utility will have Open-EJB available on the classpath to get implementations of all the Java EE 6 classes.
Even though the EJB project is built to run on Hibernate, the utility should not be Hibernate-specific.
Are there any stumbling blocks?
In case anyone's interested, Solution 1 worked. Here's essentially what I had to do:
public MySQLSchemaGenerator() throws ClassNotFoundException {
Properties mySQLDialectProps = new Properties();
mySQLDialectProps.setProperty("javax.persistence.transactionType", "RESOURCE_LOCAL");
mySQLDialectProps.setProperty("javax.persistence.jtaDataSource", "");
final EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence_unit_name>", mySQLDialectProps);
final Metamodel mm = emf.getMetamodel();
for (final ManagedType<?> managedType : mm.getManagedTypes()) {
managedType.getJavaType(); // this returns the java class of the #Entity object
}
}
The key was to override my transaction type and blank out the jtaDataSource which had been defined in my persistence.xml. Turns out everything else was unnecessary.
If Your jar is well-formed (persistence.xml at the right place - in the META-INF folder), then all looks fine.
It is not necessary to run your utility inside a container, JPA is not a part of JavaEE specs.

Testing ServiceLoader in Eclipse Plugins

I have four Eclipse plugin projects (create a new Java Project, right-click, configure, Convert to Plugin Project) in my workspace. The first (my.runtime) contains an interface (MyFactoryInterface) and a class (MyClient) that defines a method (List<String> getAllFactoryNames()) that loads all implementations of that interface via java.util.ServiceLoader and calls a method (String getName()) on them, collecting the results and returning them in a list.
To test that class, I have a JUnit test in the second project (my.runtime.test, set up with my.runtime as Fragment-Host), checking if the name returned by a dummy implementation(MyDummy, returning "Dummy") I have in the my.runtime.test project is in the list returned by MyClient.getAllFactoryNames(). So far, it works fine.
In the third project (my.extension, with my.runtime as dependency) I have a class (MyHello) that uses the names returned by MyClient.getAllFactoryNames() to return a list of greetings ("Hello "+name).
Again, to test this, I have a project (my.extension.test, with my.extension as Fragment-Host) containing another Implementation (MyWorld, returning "World" as name) and a JUnit test case checking if "Hello World" is in the greetings returned by MyHello.getGreetings(). This test fails, as MyClient still only finds the MyDummy implementation, and not the MyWorld implementation. Both implementations are accompanied by matching entries in META-INF/services/my.runtime.MyFactoryInterface files.
I currently use the following code to load the implementations:
ServiceLoader<MyFactoryInterface> myFactoryLoader = ServiceLoader.load(MyFactoryInterface.class);
for (MyFactoryInterface myFactory : myFactoryLoader) {
I know that I can supply a ClassLoader as a second argument to ServiceLoader.load, but I have no idea how to get one that knows all plugin projects... any suggestions? Or is ServiceLoader not the right tool for this problem?
If anyone stumbles over the same problem: the combination of ServiceLoader.load(MyFactoryInterface.class, Thread.currentThread().getContextClassLoader()) in MyClient and Thread.currentThread().setContextClassLoader(MyWorld.class.getClassLoader()); in the second test did the job.

Categories

Resources