How can I use Eclipse's new Xtend language in

2019-03-11 02:41发布

问题:

I'd like to write Java classes in the Xtend language (simply because its way more terse), and have it compile back down into Java classes of which I can use in my Java project. Just like coffeescript. How can I do this?

I tried creating an Xtend file just as I would do with a new class, however I get this error:

Mandatory library bundle 'org.eclipse.xtext.xbase.lib' not found on the classpath.

This disables intellisense (autocompletion). Also, even if I do get that working, how can I have it compile to a Java class?

回答1:

Having tried the same thing, I can confirm that enabling the Xtend Nature and adding the three Xtend libraries (mentioned earlier, 'org.eclipse.xtext.xtend2.lib', 'org.eclipse.xtext.xbase.lib' and 'com.google.inject') to the project's libraries makes the Xtend code compile, at least. However, I am also having trouble with the R class.

On closer inspection, it looks like the problem with the R class is not with it being located in a different directory. Copying the file to the main source dir with a different name doesn't change anything. Rather, it looks like the problem is with the R class being a static final class, containing several static final subclasses. If I create a simple plain-Java wrapper class that wraps a reference to R.layout.main (for example) inside a normal method, and call that from my Xtend code, then it does accept it and happily compiles.

After that, the next issue I came across was the Android compiler complaining about duplicate about.html and plugin.properties files in 'org.eclipse.xtext.xtend2.lib', 'org.eclipse.xtext.xbase.lib' and 'com.google.inject'. That is relatively easy to fix, by removing those files from two of the three .jar files. I'm not sure if it breaks anything later on, but now at least I have a working snippet of Xtend code running on the Android emulator.



回答2:

In Xtend inner classes are dereferenced using a dollar sign ('$') and static members are accessed using a double colon ('::').

The HelloAndroid activity code would look like this:

class XtendActivity extends Activity {

    override void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R$layout::main);
    }
}


回答3:

I just got it to compile, though I cannot import the "R" class, for now. Execute these steps:

First, install the Xtend SDK in the Eclipse update manager, by entering "http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/", expanding node "TMF Xtext-2.1.0", and selecting "Xtend2 SDK". Wait, then restart Eclipse.

In your Eclipse Android project folder, edit file ".project" (e.g. by typing "nano .project" in Terminal on OSX), and change it so that it resembles this (except for the name; you can actually copy the whole content over and change the name back to your project name):

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>TestAndroidXtend</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
    <buildCommand>
        <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
        <arguments>
        </arguments>
    </buildCommand>
    <buildCommand>
        <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
        <arguments>
        </arguments>
    </buildCommand>
    <buildCommand>
        <name>org.eclipse.jdt.core.javabuilder</name>
        <arguments>
        </arguments>
    </buildCommand>
    <buildCommand>
        <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
        <arguments>
        </arguments>
    </buildCommand>
    <buildCommand>
        <name>com.android.ide.eclipse.adt.ApkBuilder</name>
        <arguments>
        </arguments>
    </buildCommand>
</buildSpec>
<natures>
    <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
    <nature>org.eclipse.jdt.core.javanature</nature>
    <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>

Then insert the following into file ".classpath", within the classpath element:

<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>

I put it before the entry with com.android.ide.eclipse.adt.ANDROID_FRAMEWORK, perhaps you should do that too.

Back in Eclipse, refresh the project with F5, then create a folder "META-INF" at the toplevel of the project, and create an empty file "MANIFEST.MF". Paste into it these contents:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Xtend Tutorial
Bundle-SymbolicName: xtend.tutorial
Bundle-Version: 2.1.0.qualifier
Bundle-Vendor: Eclipse Modeling
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Require-Bundle: org.eclipse.xtext.xtend2.lib;bundle-version="2.0.0",
 org.junit4,
 org.aopalliance;bundle-version="1.0.0"

Perform a "Project" -> "Clean" on your project, and you can now create and use Xtend classes.

As mentioned before, I cannot import the R class, perhaps Xtend just looks in the normal "src" folder for class files.



回答4:

I haven't done any Android development so far. But Xtend code is compiled against a thin runtime library (written in Java). It's mainly just three jars: - org.eclipse.xtext.xtend2.lib - org.eclipse.xtext.xbase.lib - com.google.collect

They are all installed in eclipse, so you should find them in the plugins folder of your installation. We usually use OSGI and PDE to have them on the classpath, but it's really just a classpath dependency.

Xtend can import everything which is on the classpath just like Java. It reuses the Java project configuration and also the Java Development Tools. So as long as you have the "R" class on the class path it should work. Please file a bugzilla at bugs.eclipse.org (under Modeling/TMF/Xtext) If you can't reference it although you can from a Java which sits next to the Xtend file. And provide a small example and some additional explanation.



回答5:

Here's another gotcha: Make sure your parameter names don't conflict with anything in R.java.

I created a (Java) Activity using the wizard, copied the code, deleted the Activity, and created a MainActivity.xtend in its place, like so:


public class MainActivity extends Activity {

    override void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R$layout::activity_main);
    }

    override boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R$menu::activity_main, menu);
        return true;
    }

It looks fine in the .xtend file, but it doesn't build because the generated Java code

  public boolean onCreateOptionsMenu(final Menu menu) {
    MenuInflater _menuInflater = this.getMenuInflater();
    _menuInflater.inflate(menu.activity_main, menu);
    return true;
  }

doesn't like activity_main at this point.

It took me a few minutes to figure out that the "menu" parameter was overriding R.menu.activity_main. Once I changed the .xtend's "menu" parameter to "optionsMenu", it worked fine.