I have an enum defined top-level inside a Groovy class which I want to use in another class that is located in another source file:
// File: A.groovy
package com.example.pkg
class A {
static enum E {
VALUE
}
}
// File: B.groovy
package com.example.pkg
import package com.example.pkg.A
class B {
void example() {
final enumValue = A.E.VALUE
^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- unable to resolve class 'A.E'
}
}
Whenever I try to access the enum the Java-way, I get an 'unable to resolve class A.E' error.
Am I doing something wrong? I cannot find any useful information online.
Thanks in advance!
How can I extend an existing package / library in Dart?
e.g.
import 'package:eventify/eventify.dart';
extend EventEmitter { // <- object from package
once() {
// my code here
}
}
void main() {
EventEmitter().once(...);
}
It is possible from dart 2.6 (which is currently in dev)
feature specification example
For example:
extension MyEmitter on EventEmitter {
once() {
// code here
}
}
From my understanding, not possible yet, although it has been proposed for a future Dart release.
In Xtext, how do I follow a reference from grammar B to grammar A, within a validator of grammar B (which is in the ui-plugin)? Consider the following example.
Grammar A is org.xtext.people.People
grammar org.xtext.people.People with org.eclipse.xtext.common.Terminals
generate people "http://www.xtext.org/people/People"
People:
people+=Person*;
Person:
'person' name=ID ';';
and an instance
person Alice {citizenship "MN"; id "12345"; }
person Bob {citizenship "CH"; id "54321";}
person Malice {citizenship "XXX"; id "66666"; }
At an airport, entries of people are recorded.
enter Alice;
enter Bob;
enter Malice;
Entries are modelled with a second grammar B org.xtext.entries.Entries
grammar org.xtext.entries.Entries with org.eclipse.xtext.common.Terminals
generate entries "http://www.xtext.org/entries/Entries"
import "http://www.xtext.org/people/People"
Entries:
entries+=Entry*;
Entry:
'enter' person=[Person] ';';
After ensuring that the Eclipse project org.xtext.entries has the project org.xtext.people on it's classpath, and ensuring that the org.xtext.entries plugin has the org.xtext.people as a dependency, all works as expected.
There is a travel ban on people from country XXX, although certain deserving people are excluded. Only the CIA knows who is excluded from the ban. Entries must not be allowed for people from XXX unless excluded.
The updated grammar is
grammar org.xtext.entries.Entries with org.eclipse.xtext.common.Terminals
generate entries "http://www.xtext.org/entries/Entries"
import "http://www.xtext.org/people/People"
Entries:
entries+=Entry*;
Entry:
travelBanOverride=TravelBanOverride?
'enter' person=[Person] ';';
TravelBanOverride: '#TravelBanOverride' '(' code=STRING ')';
with validator
package org.xtext.entries.validation
import org.eclipse.xtext.validation.Check
import org.xtext.entries.entries.EntriesPackage
import org.xtext.entries.entries.Entry
import org.xtext.entries.CIA
class EntriesValidator extends AbstractEntriesValidator {
public static val BAN = 'BAN'
public static val ILLEGAL_OVERRIDE = 'ILLEGAL_OVERRIDE'
#Check
def checkBan(Entry entry) {
if (entry.person.citizenship == "XXX") {
if (entry.travelBanOverride === null) {
error('Violation of Travel Ban', EntriesPackage.Literals.ENTRY__PERSON, BAN)
}
else {
val overridecode = entry.travelBanOverride.code;
val valid = CIA.valid(entry.person.name, entry.person.id, overridecode)
if (!valid) {
error('Illegal override code', EntriesPackage.Literals.ENTRY__TRAVEL_BAN_OVERRIDE, ILLEGAL_OVERRIDE)
}
}
}
}
}
where the driver for the external CIA web-app is modelled for example by
package org.xtext.entries;
public class CIA {
public static boolean valid(String name, String id, String overrideCode) {
System.out.println("UNValid["+name+","+overrideCode+"]");
return name.equals("Malice") && id.equals("66666") && overrideCode.equals("123");
}
}
The validations work as expected.
I now wish to provided a quick-fix for BAN, that checks for an override code from the CIA.
package org.xtext.entries.ui.quickfix
import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider
import org.eclipse.xtext.ui.editor.quickfix.Fix
import org.xtext.entries.validation.EntriesValidator
import org.eclipse.xtext.validation.Issue
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor
import org.xtext.entries.entries.Entry
import org.xtext.entries.Helper
class EntriesQuickfixProvider extends DefaultQuickfixProvider {
#Fix(EntriesValidator.BAN)
def tryOverride(Issue issue, IssueResolutionAcceptor acceptor) {
acceptor.accept(issue, 'Try override', 'Override if CIA says so.', 'override.png')
[element ,context |
val entry = element as Entry
// val person = entry.person // no such attribute
//val person = Helper.get(entry); // The method get(Entry) from the type Helper refers to the missing type Object
]
}
}
The first commented line does not compile: there is no attribute person. The second commented line is an attempt to solve the problem by getting a helper class in org.xtext.entries to get the person, but this does not compile either, giving a "The method get(Entry) from the type Helper refers to the missing type Object" error message.
For completeness, here is that helper.
package org.xtext.entries
import org.xtext.people.people.Person
import org.xtext.entries.entries.Entry
class Helper {
static def Person get(Entry entry) {
return entry.person;
}
}
Further, entry.travelBanOverride compiles fine, but entry.person does not. Clicking on Entry in Eclipse takes one to the expected code, which has both travelBanOverride and person.
The issue does not occur with a Java class in the same project and package.
package org.xtext.entries.ui.quickfix;
import org.xtext.entries.entries.Entry;
import org.xtext.people.people.Person;
public class Test {
public static void main(String[] args) {
Entry entry = null;
Person p = entry.getPerson();
}
}
Rewriting the quickfix in Java solves the problem.
package org.xtext.entries.ui.quickfix;
import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider;
import org.eclipse.xtext.ui.editor.quickfix.Fix;
import org.xtext.entries.validation.EntriesValidator;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor;
import org.xtext.entries.entries.Entry;
import org.xtext.entries.Helper;
import org.eclipse.xtext.ui.editor.model.edit.IModificationContext;
import org.eclipse.xtext.ui.editor.model.edit.ISemanticModification;
import org.eclipse.emf.ecore.EObject;
import org.xtext.entries.entries.Entry;
import org.xtext.people.people.Person;
public class EntriesQuickfixProvider extends DefaultQuickfixProvider {
#Fix(EntriesValidator.BAN)
public void tryOverride(final Issue issue, IssueResolutionAcceptor acceptor) {
acceptor.accept(issue,
"Try to override",
"Override",
"override.gif",
new ISemanticModification() {
public void apply(EObject element, IModificationContext context) {
Entry entry = (Entry) element;
System.out.println(entry.getPerson());
}
}
);
}
}
How do I follow a reference from grammar B (Entries) to grammar A (People), within a validator of grammar B?
My mistake is the following.
After ensuring that the Eclipse project org.xtext.entries has the
project org.xtext.people on it's classpath, and ensuring that the
org.xtext.entries plugin has the org.xtext.people as a dependency, all
works as expected.
The org.xtext.entries.ui ui-plugin must also have the org.xtext.people on its Java (Eclipse project) build path. Exporting and making a plugin-dependency it not enough.
Note that this setting should be made early, before crafting the quick-fix, because the Xtend editor has refreshing issues.
I'm trying to get the properties of a dynamic Class name (also trying to instantiate it) but the next code doesn't work because I think I need to import the dart file that has the Class code in the file where I want to reflect it:
//I import the file in other Dart file
import 'MyClass.dart'; //This only have a class named MyClass with some properties
import 'OtherClass.dart'
class mainClass {
void mainFunction () {
var properties = OtherClass.getProperties('MyClass');
}
}
Here is the OtherClass contents:
import "dart:mirrors";
class OtherClass {
static getProperties (String className) {
ClassMirror cm = reflectClass(className);
for (var m in cm.declarations.values)
print(MirrorSystem.getName(m.simpleName));
}
}
is there anyway to reflect a class that is not imported in the actual Dart file?
Hope this makes sense, thanks in advance.
You need to find the library containing the class first. Use currentMirrorSystem().libraries to get all libraries imported in your application. If you want to avoid disambiguities, add unique library declarations to your library and pass the library name to getProperties() for exact lookups.
import "dart:mirrors";
class OtherClass {
static getProperties(String className) {
var classSymbol = new Symbol(className);
var libs = currentMirrorSystem().libraries;
var foundLibs = libs.keys.where((lm) =>
libs[lm].declarations.containsKey(classSymbol) &&
libs[lm].declarations[classSymbol] is ClassMirror);
if (foundLibs.length != 1) {
throw 'None or more than one library containing "${className}" class found';
}
ClassMirror cm = libs[foundLibs.first].declarations[classSymbol];
for (var m
in cm.declarations.values) print(MirrorSystem.getName(m.simpleName));
}
}
Say i got 3 dart scripts in the same folder.
// a.dart
import 'b.dart';
void main(){
print(foo);
}
// b.dart
import 'c.dart';
// c.dart
var foo = 1;
and I got Cannot resolve 'foo' in a.dart
Import doesn't automatically reexport.
You can use one of these variants:
// b.dart
import 'c.dart';
export 'c.dart';
// foo is available in b.dart and a.dart
or
// b.dart
export 'c.dart';
// foo is not available in b.dart but in a.dart
This is the same as my answer to How can I import all files in a folder? was about ;-)
A few alternate options.
Option 1
Solely use import statements and reference the actually files you need. For example:
// a.dart
import 'b.dart';
import 'c.dart';
void main(){
print(foo);
print(bar);
}
// b.dart
import 'c.dart';
var bar = foo + 1;
// c.dart
var foo = 1;
This doesn't allow for inherited imports, but if you follow this pattern throughout your app, your dependencies are very easy to see (they won't be hidden in another file).
Option 2
Don't use imports, but rather just make everything part of the same library.
// a.dart
library myLib;
part 'b.dart';
part 'c.dart';
void main(){
print(foo);
print(bar);
}
// b.dart
part of myLib;
var bar = foo + 1;
// c.dart
part of myLib;
var foo = 1;
This option works well if your application isn't too large and all your classes and global variables have unique names (that is to say you don't nee namespacing). You can also implement this pattern into a small subsection of your applicaiton rather than the whole thing.