Restrict Xtext scoping to folder - xtext

When having two Xtext models in the same project but in different folders using the same names (ID) for different objects, the scoping does not work how I want it to. How can I restrict the scoping to inside one folder and not the whole project?
Example:
grammar:
Model:
persons+=Person*
greetings+=Greeting*;
Greeting:
'Hello' name=[Person] '!';
Person:
'person' name=ID;
folder structure:
project
|-folder1
|-person1.mydsl
|-folder2
|-greeting.mydsl
|-person2.mydsl
person1.mydsl contains a Person ("Jane"), person2.mydsl also contains a Person ("Jane") and greeting.mydsl contains a Greeting ("Hello Jane!") referencing the person in person1.mydsl instead of the person in person2.mydsl.
The documentation tells me to use the StateBasedContainerManager but I don't understand where and how.

Thanks to #Christian and this I found a solution. So first adding a filter to the DefaultGlobalScopeProvider
public class MyGlobalScopeProvider extends DefaultGlobalScopeProvider {
#Override
public IScope getScope(Resource resource, EReference reference, Predicate<IEObjectDescription> filter) {
filter = new Predicate<IEObjectDescription>() {
#Override
public boolean apply(IEObjectDescription input) {
// implement here
}
};
return super.getScope(resource, reference, filter);
}
}
and then telling my runtime module to use my provider instead
public class MyDslRuntimeModule extends AbstractMyDslRuntimeModule {
#Override
public Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() {
return MyGlobalScopeProvider.class;
}
}

Related

Dart abstract optional parameters

How can I abstract that a methods has optional parameters?
abstract class CopyWith<T>{
T copyWith({}); // Error : Expected an identifier.
}
If I add an identifier like {test} it works and subclasses can have additional arguments
What I want to achieve?
I have a complex state manager, I make some abstraction , the following code is a minimal code, show my problem
import 'dart:collection';
abstract class CopyWith<T> {
T copyWith(OPTIONAL_NAMED_ARGUMENTS);
}
abstract class Manager<K, V extends CopyWith> {
final _map = HashMap<K, V>();
add(K key,V value){
_map[key] = value;
}
void copyWith(K key,OPTIONAL_NAMED_ARGUMENTS) {
assert(key != null);
if (_map.containsKey(key)) {
_map[key].copyWith(OPTIONAL_NAMED_ARGUMENTS);
}
}
}
class User implements CopyWith {
final int id;
final String name;
User({this.id, this.name});
User copyWith({int id, String name}) {
return User(
id: id ?? this.id,
name: name ?? this.name,
);
}
}
class UserManager extends Manager<int, User> {}
void main() {
final userManager = UserManager();
userManager.add(1,User(1,'test'));
userManager.copyWith(1,{test:'test2'})
}
As some one who has faced this issue in my library, I would say the only way is to not put a copyWith in your base class.
Why? Because you should only make a function polymorphic when there IS actually a shared calling convention and behavior. In your example, The way that these two classes perform copyWith is just different. It is, and should be, an error to send a name to Manager.copyWith, because Manager does not have a name to begin with. If you encounter a name inside a Manager.copyWith, that means there is some serious error in your code.
Also, if you actually try to invoke copyWith, as a responsible programmer, you will probably check if you are allowed to pass a name, which is,
if (someObj is User) {
someObj.copyWith(key, name: name);
} else if (someObj is Manager) {
throw IllegalStateError('You should not pass a name to a Manager! What am I supposed to do with the name now?');
}
There, you have already done type checking, so no need to make copyWith polymorphic.
However, some common behaviors can be made polymorphic, like updateKey. You can make Keyable as an interface, and Keyable updateKey(Key key) as an abstract method, and delegate to a non-polymorphic copyWith inside each subclasses.

Getting an injected object using CDI Produces

I have a class (OmeletteMaker) that contains an injected field (Vegetable). I would like to write a producer that instantiates an injected object of this class. If I use 'new', the result will not use injection. If I try to use a WeldContainer, I get an exception, since OmeletteMaker is #Alternative. Is there a third way to achieve this?
Here is my code:
#Alternative
public class OmeletteMaker implements EggMaker {
#Inject
Vegetable vegetable;
#Override
public String toString() {
return "Omelette: " + vegetable;
}
}
a vegetable for injection:
public class Tomato implements Vegetable {
#Override
public String toString() {
return "Tomato";
}
}
main file
public class CafeteriaMainApp {
public static WeldContainer container = new Weld().initialize();
public static void main(String[] args) {
Restaurant restaurant = (Restaurant) container.instance().select(Restaurant.class).get();
System.out.println(restaurant);
}
#Produces
public EggMaker eggMakerGenerator() {
return new OmeletteMaker();
}
}
The result I get is "Restaurant: Omelette: null", While I'd like to get "Restaurant: Omelette: Tomato"
If you provide OmeletteMaker yourself, its fields will not be injected by the CDI container. To use #Alternative, don't forget specifying it in the beans.xml and let the container instantiate the EggMaker instance:
<alternatives>
<class>your.package.path.OmeletteMaker</class>
</alternatives>
If you only want to implement this with Producer method then my answer may be inappropriate. I don't think it is possible (with standard CDI). The docs says: Producer methods provide a way to inject objects that are not beans, objects whose values may vary at runtime, and objects that require custom initialization.
Thanks Kukeltje for pointing to the other CDI question in comment:
With CDI extensions like Deltaspike, it is possible to inject the fields into an object created with new, simply with BeanProvider#injectFileds. I tested this myself:
#Produces
public EggMaker eggMakerProducer() {
EggMaker eggMaker = new OmeletteMaker();
BeanProvider.injectFields(eggMaker);
return eggMaker;
}

How to inject a list with different implementations of the same interface in a nested module scenario via Guice?

There is an interface DCE, which is implemented by a class DCEImpl which has a dependency, say, string S, which it gets via its constructor.
The universe of S is limited, say S can only take values {'A','B','C'}.
There is an already existing Guice module that accepts the value of S in its constructor, and then binds the interface DCE to the correctly initialized version of DCEImpl.
public class DCEModule extends AbstractModule {
private final String s;
public DCEModule(String s){
this.s = s;
}
protected void configure() {
bind(DCE.class).toInstance(new DCEImpl(s));
}
}
Now I have a class C which needs a List<DCE> with all the 3 implementations (actually a lot more than 3, using 3 for example purpose).
I want to inject this list via Guice in C. To do that, I created a new module DCEPModule, which will provide a List<DCE> in this way:
#Provides
List<DCE> getDCE() {
for(String s: S){
Module m = new DCEModule(s);
install(m);
Injector injector = Guice.createInjector(m);
listDomains.add(injector.getInstance(DCE.class));
}
}
My problem is that I don't want to call a new injector in this module, because DCEPModule will be installed by a different module.
public class NewModule extends AbstractModule {
protected void configure() {
install(DCEPModule);
}
}
I want a way to get the List<DCE> without explicitly creating a new injector in DCEPModule.
You can achieve this by using a Multibinder (javadoc, wiki).
Here’s an example:
public class SnacksModule extends AbstractModule {
protected void configure(){
Multibinder<Snack> multibinder = Multibinder.newSetBinder(binder(), Snack.class);
multibinder.addBinding().toInstance(new Twix());
  multibinder.addBinding().toProvider(SnickersProvider.class);
  multibinder.addBinding().to(Skittles.class);
}
}
Now, the multibinder will provide a Set<Snack>. If you absolutely need a List instead of a Set, then you can add a method to your module like this:
#Provides
public List<Snack> getSnackList(Set<Snack> snackSet) {
return new ArrayList(snackSet);
}
You can add implementations to the same Multibinding in more than one module. When you call Multibinder.newSetBinder(binder, type) it doesn’t necessarily create a new Multibinding. If a Multibinding already exists for for that type, then you will get the existing Multibinding.

neo4j java node dynamic properties

I am trying to create nodes of a specific type with properties which can be dynamic .
For Example : I can create a Person node with name,age,address properties. But these need not be the only properties when I create another Person node. This node can have name,age,address and an additional property salary. Using spring data or query DSL needs me to create Java POJO class Person with fixed number of instance variables name,age and address .
#NodeEntity
public class Person {
#GraphId private Long id;
private String name;
private String age;
private String address;
}
I cannot add a dynamic property for salary for another Person node. Is there a way I can achieve this ?
Dynamic properties are not supported in Neo4j-OGM at the moment (see https://jira.spring.io/browse/DATAGRAPH-555)
If you only interact with your graph via the OGM and do not have to query on individual dynamic properties, you could try a Map of properties with a custom Converter, that converts this Map to a String (like json). The OGM will then use this converter to serialize the map to and from the graph.
Note that because the values are squashed into a String, it is now not trivial to query on an individual dynamic property.
To create a custom converter you need to implement org.neo4j.ogm.typeconversion.AttributeConverter and provide the implementation to convert from a Map to String.
Then, annotate your map property in your domain entity like this:
#Convert(MoneyConverter.class)
Edit:
As pointed out by Michael, if the salary is the only extra optional property, then it makes sense to have this property but set it only when it has a value. Dynamic properties are overkill in this case. You may want to use dynamic properties when you have an unknown and arbitrary set of properties to be persisted with the node
You can workaround the limitations by creating a CompositeAttributeConverter saving each dynamic property in the graph (not only as JSON-String wich cannot be queried well - as mentioned by luanne in the accepted answer)
import java.lang.reflect.Field;
import java.util.*;
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
public abstract class DynamicPropertiesConverter implements CompositeAttributeConverter<Map<String, ?>> {
private Set<String> blacklist;
public DynamicPropertiesConverter(Class<?> clazz) {
blacklist = new HashSet<>();
addAllFields(clazz);
}
public DynamicPropertiesConverter(Set<String> blacklist) {
this.blacklist = blacklist;
}
public void addAllFields(Class<?> type) {
for (Field field : type.getDeclaredFields()) {
blacklist.add(field.getName());
}
if (type.getSuperclass() != null) {
addAllFields(type.getSuperclass());
}
}
#Override
public Map<String, ?> toGraphProperties(Map<String, ?> value) {
Map<String, ?> result = new HashMap<>(value);
result.keySet().removeAll(blacklist);
return result;
}
#Override
public Map<String, ?> toEntityAttribute(Map<String, ?> value) {
return toGraphProperties(value);
}
}
Now you can create a special version of this converter:
public class DynamicNodePropertiesConverter extends DynamicPropertiesConverter {
public DynamicNodePropertiesConverter() {
super(Node.class);
}
}
And use it like this:
import java.util.Map;
import DynamicNodePropertiesConverter;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.typeconversion.Convert;
#NodeEntity
public class Node {
#Convert(DynamicNodePropertiesConverter.class)
private Map<String, Object> data;
/* getter and setter */
}

Guice - How to use binding annotations to build a list of objects

I have created Guice binding annotations that allow me to bind two different instances of a class depending on the annotation e.g.:
bind(Animal.class).withAnnotation(Cat.class).toInstance(new Animal("Meow"));
bind(Animal.class).withAnnotation(Dog.class).toInstance(new Animal("Woof"));
I was hoping to be able to create a provider method that provides a List that is a dependency for one of my classes, but can't figure out how to use the annotations for this:
#Provider
List<Animal> provideAnimalList() {
List<Animal> animals = new ArrayList<Animal>();
animals.add(#Cat Animal.class); // No, but this is what I want
animals.add(#Dog Animal.class); // No, but this is what I want
return animals;
}
So I was assuming that I would just be able to use the annotations in the argument to add() method of the List... but no.
How should I be approaching this? It seems to me it would be simpler simply to new the two instances of the Animal class and maybe this is not how the binding annotations were meant to be used.
I'd appreciate comments on the best use of the binding annotations in this scenario.
Thanks
If it is really what you want, here a working solution :
public class AnimalModule extends AbstractModule {
#Override
protected void configure() {
bind(Animal.class).annotatedWith(Cat.class).toInstance(new Animal("Meow"));
bind(Animal.class).annotatedWith(Dog.class).toInstance(new Animal("Woof"));
}
#Provides
List<Animal> provideAnimalList(#Cat Animal cat, #Dog Animal dog) {
List<Animal> animals = new ArrayList<Animal>();
animals.add(cat);
animals.add(dog);
return animals;
}
public static void main(String[] args) {
List<Animal> animals = Guice.createInjector(new AnimalModule()).getInstance(Key.get(new TypeLiteral<List<Animal>>() {
}));
for (Animal animal : animals) {
System.out.println(animal);
}
}
}
Annotations :
#Retention(value = RetentionPolicy.RUNTIME)
#BindingAnnotation
public #interface Cat {
}
Output :
Animal{sound='Meow'}
Animal{sound='Woof'}
However :
Don't create specific annotations, seems unnecessary in that case. Use #Named instead,
You may consider Multibindings to solve that problem.

Resources