I'm working on xtext project and I'm generating objects through .xtext file.
I want to add new attribute to one of the generated object.
I saw in http://christiandietrich.wordpress.com/2011/07/22/customizing-xtext-metamodel-inference-using-xtend2/
the following code is generating a temp variable in ObjectValue
but i want temp to be of type MyObject.
How to do so? where can i read about it?
import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage
import org.eclipse.emf.common.util.BasicEMap$Entry
import org.eclipse.emf.ecore.EClass
import org.eclipse.emf.ecore.EPackage
import org.eclipse.emf.ecore.EcoreFactory
import org.eclipse.emf.ecore.EcorePackage
import org.eclipse.xtext.GeneratedMetamodel
import org.eclipse.xtext.xtext.ecoreInference.IXtext2EcorePostProcessor
class CodeGeneratorClass implements IXtext2EcorePostProcessor {
override process(GeneratedMetamodel metamodel) {
metamodel.EPackage.process
}
def process(EPackage p) {
for (c : p.EClassifiers.filter(typeof(EClass))) {
if (c.name == "ObjectValue") {
c.handle
}
}
}
def handle (EClass c) {
val attr = EcoreFactory::eINSTANCE.createEAttribute
attr.name = "temp"
attr.EType = EcorePackage::eINSTANCE.EString
c.EStructuralFeatures += attr
}
}
First: MyObject must be described either by an EClass or an EDataType. A plain Java Object won't do it.
If MyObject is an EDataType then you must add an EAttribute in the handle method. Your handle method is almost right, only the EType must be adjusted:
attr.EType = MyPackage::eINSTANCE.MyObject
Otherwise: If MyObject is an EClass then you must add an EReference instead of an EAttribute. The handle method for this case looks like this:
def handleReference(EClass c){
val ref = EcoreFactory::eINSTANCE.createEReference
ref.name = "temp"
ref.EType = MyPackage::eINSTANCE.MyObject
c.EStructuralFeatures += ref
}
EDIT
In order to define a new, minimal EDataType and hook it up into the model the following snippet should work:
def void process(GeneratedMetamodel it){
// create new dynamic EDataType
val dataType = EcoreFactory::eINSTANCE.createEDataType => [
name = 'MyObject'
instanceTypeName = 'java.package.with.MyObject'
]
// register new EDataType in own model package
EPackage.EClassifiers += dataType
// attach as EAttribute to appropriate EClasses
EPackage.EClassifiers.filter(typeof(EClass)).filter[name == 'ObjectValue'].forEach[
EStructuralFeatures += EcoreFactory::eINSTANCE.createEAttribute => [
name = "temp"
EType = dataType
]
]
}
Related
I came to know that dart mirrors is disabled in flutter but hope that there might be some alternate way to achieve. Mirrors must not be disabled in flutter, it is an important & must have feature.
import 'package:reflectable/mirrors.dart';
import 'package:reflectable/reflectable.dart';
const reflector = const Reflector();
class Reflector extends Reflectable
{
const Reflector() : super(
invokingCapability,
typingCapability,
reflectedTypeCapability,
);
}
#reflector
class Dictionary
{
String english, myLang;
int index;
}
main() {
test();
}
test()
{
ClassMirror classMirror = reflector.reflectType(Dictionary);
classMirror.declarations.values.forEach((field)
{
VariableMirror variableMirror = field;
/*??????????????????????????????????????????
Now How To Get Field types i.e. String & int
How to instantiate class object
How to set fields values
???????????????????????????????????????????*/
});
}
Runtime object instantiation:
Use the method newInstance from ClassMirror. The first argument is the constructor name. Like you haven't name constructors, simple pass an empty string. The second argument are an array of positional constructor arguments. No constructor, empty array.
Dictionary dic = classMirror.newInstance("", []);
Set fields values:
Use the method invokeSetter from InstanceMirror. The first argument is the field name and the second is the value.
InstanceMirror instanceMirror = reflector.reflect(dic);
instanceMirror.invokeSetter("index", 3);
So far I am able to know field(s) type:
ClassMirror classMirror = reflector.reflectType(Dictionary);
VariableMirror variableMirror = classMirror.declarations["english"] as VariableMirror;
Type type = variableMirror.dynamicReflectedType;
print("field: " + variableMirror.simpleName + " has type: " + type.toString());
Now remaining:
Runtime object instantiation?
How to set fields value of instantiated object?
I know this is a very fundamental question but answer to this will solve many of my doubts.
val new_parent = ParentDetails(intent.extras.getString("name"),
intent.extras.getString("email"),
intent.extras.getString("parent_relation"),
intent.extras.getString("locationdata"))
println(new_parent.tostring())
The code above doesn't print the various fields and their values present in the class.
The ParentDetails is a model I have created with some fields that are initialized. The ParentDetails model:
class ParentDetails {
var parent_id: Int = 0
var parent_name: String = ""
var parent_email: String = ""
var parent_relation: String = ""
var parent_location: String=""
constructor(parent_name: String, parent_email: String, parent_relation: String,parent_location:String) {
this.parent_name = parent_name
this.parent_email = parent_email
this.parent_relation = parent_relation
this.parent_location = parent_location
}
public fun getparentId(): Int {
return parent_id
}
fun ParentDetailsprintme() {
println(parent_name)
println(parent_email)
println(parent_relation)
println(parent_location)
}
}
In fact, it prints null and accessing individual fields, it prints empty string(the way it was initialized).
How do we explain this?
As I understand your problem is that calling println(new_parent.tostring()) does not print what you would like to print in function ParentDetailsprintme.
First of all, you have a typo, the correct call would be new_parent.toString().
Note that it could have been simplified as println(new_parent).
It does not print that you defined in the ParentDetailsprintme method, as the method is not called.
What println(new_parent.toString()) prints, is actually the hashcode of the object, as this is the default behaviour of every object.
To make it work call it like println(new_parent.ParentDetailsprintme()) or override the toString() method for example as:
override fun toString() = "$parent_name $parent_email $parent_relation $parent_location"
then the following
val new_parent = ParentDetails("myName", "myEmail", "myParent_relation", "myLocationdata")
println(new_parent)
should print
myName myEmail myParent_relation myLocationdata
Kotlin's println function simply calls System.out.println(message) under the hood which will call String.valueOf() (e.g. String.valueOf(Object object) for objects, which will call the toString() method of the passed object).
/** Prints the given message and newline to the standard output stream. */
#kotlin.internal.InlineOnly
public inline fun println(message: CharArray) {
System.out.println(message)
}
Update ("Using data class method also works"):
If you make the class to be a data class:
data class ParentDetails(
val parent_id: Int = 0,
val parent_name: String = "",
val parent_email: String = "",
val parent_relation: String = "",
val parent_location: String = ""
)
and then you execute
val new_parent = ParentDetails(0, "myName", "myEmail", "myParent_relation", "myLocationdata")
println(new_parent)
you will receive as result
ParentDetails(parent_id=0, parent_name=myName, parent_email=myEmail, parent_relation=myParent_relation, parent_location=myLocationdata)
This is because data classes override the toString() function:
The compiler automatically derives the following members from all
properties declared in the primary constructor:
equals()/hashCode() pair;
toString() of the form "User(name=John, age=42)";
Did you check that you receive valid data from your intent.extras?
Also I suggest you use data class for your models.
It will look something like this:
data class ParentDetails(
var parent_id: Int = 0,
var parent_name: String = "",
var parent_email: String = "",
var parent_relation: String = "",
var parent_location: String = ""
)
You will be able to use it like this :
val new_parent = ParentDetails(
parent_name = intent.extras.getString("name"),
parent_email = intent.extras.getString("email"),
parent_relation = intent.extras.getString("parent_relation"),
parent_location = intent.extras.getString("locationdata")
)
println(new_parent.tostring())
As already mentioned, you have a typo. toString returns the hashcode of an object unless it's overridden to return something else. Look up the original implementation for more details.
By overriding the toString method, you change what it returns, and through that, what is printed when you print(someClass). DVarga showed that in their answer.
Data classes auto-generate a toString method containing the content of the class. So creating a data class is a shortcut to getting output containing the data.
The reason the method you had didn't work is because you didn't call it. if you call it instead of toString, you would get the data printed.
Also, toString is explicitly called when you print a class. You don't need to call print(someInstance.toString()), print(someInstance) is enough.
And while I'm writing an answer, you don't need to use secondary constructors in Kotlin. Primary constructors would shorten your code significantly, whether it's a data class or not. Also, you should look into naming conventions.
I wrote a OnMethodBoundaryAspect attribute for Logging the methods exceptions.
I am in trouble with Complex method parameter.
The method signature is:
TestClass m_tf = new TestClass();
m_tf.DoWorkInternal(1, new Prova1() { ProvaP1=10, ProvaP2=11 });
I be able to trace the first parameter of type int, so i can get the parameter name and value.
But how can i get the values of the properties of the second parameters that is a complex object ?
Thanks in advance.
Giuseppe.
RESOLVED.
Found solution.
The aspect method is like this, and write the target method parameters in json format:
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
Dictionary<string, object> m_args = new Dictionary<string, object>();
for (int i = 0; i < args.Arguments.Count(); i++)
{
string name = args.Method.GetParameters()[i].Name;
object obj = args.Arguments.GetArgument(i);
m_args.Add(name, obj);
}
var output = JsonConvert.SerializeObject(m_args);
:
:
}
While you can turn the parameter/argument array into a dictionary and JSON serialize it, another way would be just find it directly using the type.
Following code should do the trick for you.
public override void OnException(MethodExecutionArgs args)
{
Prova1 prova1 = null;
var parameters = args.Method.GetParameters();
var arguments = args.Arguments
for (int i = 0; i < arguments.Count(); i++)
{
var param = parameters[i];
var arg = arguments[i];
if (param.ParameterType == typeof(Prova1))
{
prova1 = arg;
}
}
var output = prova1;
// Do your magic
base.OnException(args);
}
Also, keep in mind of two things.
System.Linq functions should be able to clean out that function a lot.
You are looping through the argument list every time there is an exception. However, the indices of your parameters never change. Thus, you should be able to calculate the index of the complex method parameter once (either in CompileTimeInitialize() or RuntimeInitialize()) and re-use that index.
continue to the example of generating a field such as:
def handle (EClass c) {
val attr = EcoreFactory::eINSTANCE.createEAttribute
attr.name = "test"
attr.EType = EcorePackage::eINSTANCE.EString
c.EStructuralFeatures += attr
}
can I generate it as a static field? how to do so?
thanks in advance,
Ecore differs from Java's object model, and unfortunately, EAttributes can't be static like fields in Java can.
Let's say I've a class myClass which has few properties, such as property1, property2, perperty3, etc. Now, I'd like to populate an array with each of those properties so that, I can access each of them through its index. Is there an automatic way of doing so?
Here's an example from SportsStore (Pro ASPN.NET MVC/Steve Sanderson/Apress) on how to gather all the active controllers in the the 'Assembly'.
var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach(Type t in controllerTypes)
//Do something
I wonder if there is some thing like the one above I can use to collect (only) properties of a class and store them in a array, no matter each one's type value (int, string, or custom type)
I hope I was able to express myself clearly. Otherwise I can amend the text.
Thanks for helping.
You could use reflection:
var foo = new
{
Prop1 = "prop1",
Prop2 = 1,
Prop3 = DateTime.Now
};
var properties = TypeDescriptor.GetProperties(foo.GetType());
var list = new ArrayList();
foreach (PropertyDescriptor property in properties)
{
var value = property.GetValue(foo);
list.Add(value);
}
and LINQ version which looks better to the eye:
var list = TypeDescriptor
.GetProperties(foo.GetType())
.Cast<PropertyDescriptor>()
.Select(x => x.GetValue(foo))
.ToArray();
I got this from here:
foreach(Type t in controllerTypes)
{
foreach (MemberInfo mi in t.GetMembers() )
{
if (mi.MemberType==MemberTypes.Property)
{
// If the member is a property, display information about the property's accessor methods
foreach ( MethodInfo am in ((PropertyInfo) mi).GetAccessors() )
{
// do something with [am]
}
}
}
}
would the Type.GetProperties() method help you?