How can I get the metaclass of a class in Delphi 7? - delphi-7

I want to raise an exception like that if an object is missing from the context object attribute list:
//******************************************************************************
EMissingContextObject = class (...)
//******************************************************************************
private
// Attributes
fAttrName : string;
fAttrType : TClass;
public
// Overiden constructors
constructor create( attrName_ : string; attrType_ : TClass );
// Properties
property attrName : string read fAttrName;
property attrType : TClass read fAttrType;
end;
//******************************************************************************
How can I pass the TClass type of an arbitrary TObject descendant? I know there is the
CClassType = class of TClassType;
definition but I don't want to depend on this declaration.
I've tried the TObject.classType, but it just works on instances.
I've tried the TypeInfo( TClassType ) but it gives back just the name of the class.
There should be something like in Java:
TClass c = TClassType.class;
or
TClass c = TClass.forName( className );
Thanks in advance!

Related

Returning object of type specified in method arguments instead of AnyRef

I have the following method:
#org.springframework.stereotype.Service
class EntityCacheManager {
def get(cacheId: String, entityClass: Class[_]): AnyRef = { ... }
//...
}
So to use it, i have to write this:
val cachedEntity = entityCacheManager.get(cacheId, classOf[SomeEntity]).asInstanceOf[SomeEntity]
Is there some way to make EntityCacheManager.get() returning instance of type entityClass which is specified in method params? I'd like to avoid casting asInstanceOf every time i use this method. I know it would be nice to use generic definition of type EntityCacheManager, but it's also a spring-managed bean, so i think using generics will cause troubles.
You can use a more idiomatic scala approach by using the ClassTag typeclass
class EntityCacheManager {
def get[T: ClassTag](cacheId: String): T = {
val entityClass = implicitly[ClassTag[T]].runtimeClass
val myObject: T = ??? // you retrieve your object somehow using entityClass
myObject
}
}
you can now use it like this:
val myEntityClassInstance = get[MyEntityClass]("key")

How to convert ODataEnumValue into its CLR enum type?

While traversing the expression tree from a FilterQueryOption, I have an instance of a ODataEnumValue. I'm wondering how to convert that into the corresponding CLR enum type value in generic way (i.e. without having to look-up the actual CLR type myself).
Maybe you can refer to ODataEnumDeserializer's ReadInline method, which convert ODataEnumvalue to CLR enum type if it is in EdmModel.
The enum type can be retrieved by getting the ClrTypeAnnotation of the TypeReference as follows. First get the model from the FilterQueryOption instance:
IEdmModel _model = filterQueryOption.Context.Model;
Then, later when parsing its FilterClause, for example for a ConstantNode:
private object GetClrValue(ConstantNode constantNode)
{
ODataEnumValue enumValue;
...
else if ((enumValue = constantNode.Value as ODataEnumValue) != null)
{
var annotation = _model.GetAnnotationValue<ClrTypeAnnotation>(constantNode.TypeReference.Definition);
Type enumType = annotation.ClrType;
parameterValue = Enum.Parse(enumType, enumValue.Value);
}
...
}

How to create a new instance of a class from string?

In my PHP Extension (Written in C) I have a string with the class name. To be more precise, I have the namespace + class name. For example: Dumb\Factory
This class implements an interface defined in my extension which has a class entry
zend_class_entry *garlic_servicemanager_factoryinterface_ce;
and implements a public method named createService
Inside another class I have a method named get and I check to see if the parameter is a string. When it is a String I would like to instantiate the class and call that method, however I don't know how to instantiate the PHP class from within my C code.
How may I instantiate a class from a string so I can call the method defined by the interface?
You have to find the class_entry from the string and you can do it like below...
zend_class_entry *ce = NULL;
char *className = "Dumb\Factory";
zend_class_entry **pce;
if (zend_lookup_class(className, strlen(className ), &pce TSRMLS_CC) == FAILURE) {
zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Class %s does not exist", className);
return;
}
ce = *pce;
// Now you have got "zend_class_entry" and
// now you can create N number of objects out of it.
// Check the Reflection API for more info.

Scala Generics - Overloaded method

Considering the given code:
val repository =
context.getBean(
Introspector.decapitalize(t.getClass.getSimpleName).replace("C", "E").concat("Repository"))
and that my repositories have a String as Serializable.
I'm trying to do the following:
repository.asInstanceOf[ElasticsearchRepository[_, String]].save(getObject(t))
This one works fine:
repository.asInstanceOf[ElasticsearchRepository[_, String]].findAll()
But I don't know how to put that above to work.
Assuming the method getObject(t) is retuning the correct object to be persisted and since it's a Spring Data Repository, there are 2 save method. One that accept a single entity and another for a list of entities and it says overloaded method value save.
What I have tried so far:
I saw in another thread to force the method with a type, something like this:
repository.asInstanceOf[ElasticsearchRepository[_, String]].save(getObject(t) : TYPE)
This is ok if I knew the type and also my method getObject should return that same type.
Here is my getObject method which I return the object itself without any specific type:
#throws[IOException]
def getObject[T](t : T) = {
objectMapper.readValue(objectMapper.writeValueAsString(t), getClazz(t))
}
So I was trying to get the type like this:
val m = Manifest.classType(getClazz(t))
type TYPE = m.type
Looks good if I force my object to this type using getObject(t) : TYPE but I don't know how to use this same type in my getObject method to be returned.
Anyway, I don't even know if this is the best approach to do this, invoking a generic repository and save a generic object.
Just to understand what I'm trying to do, I'm using a aspect to intercept a Cassandra entity to be persisted, then get it and turn into a ElasticSearch entity to save a json(thats why the getObject(t)) and replicate into ElasticSearch.
Here is the full aspect class:
#Component
#Aspect
class ElasticAop {
#Autowired val context : ApplicationContext = null
val objectMapper : ObjectMapper = new ObjectMapper()
#Pointcut("execution(* com.test.service.cassandra.*.post(..)) && args(t)")
def getPointcutPost[T](t : T) : Unit = {}
#throws[Throwable]
#Before("getPointcutPost(t)")
def elasticSaveAspect[T](joinPoint: JoinPoint, t: T) = {
val m = Manifest.classType(getClazz(t))
type TYPE = m.type
val repository =
context.getBean(
Introspector.decapitalize(t.getClass.getSimpleName).replace("C", "E").concat("Repository"))
repository.asInstanceOf[ElasticsearchRepository[_, String]].findAll()
repository.asInstanceOf[ElasticsearchRepository[_, String]].save(getObject(t))
}
#throws[ClassNotFoundException]
def getClazz[T](t : T) = {
val className = t.getClass.getName.replace("cassandra", "elastic").replace("C", "E")
Class.forName(className)
}
#throws[IOException]
def getObject[T](t : T) = {
objectMapper.readValue(objectMapper.writeValueAsString(t), getClazz(t))
}
}
EDITED
Even setting up a type return in my getObject to Address and then setting the save method as follow save(getObject(t) : Address) give me the same overloaded error.
EDITED
I just figured out it's a limitation and a possible work around is to create a factory or something like this.
Then I created a service with a saveOrUpdate method:
trait ElasticGenericService[T <: ElasticGenericKey, R <: ElasticsearchRepository[T, String]] {
var r : R = _
def saveOrUpdate(t: T) = r.save(t)
}
and now I'm getting a cast exception:
java.lang.ClassCastException: Address cannot be cast to scala.runtime.Nothing$
What i can see here:
getObject[T](t : T) returns existential type _1 and actually kills all type checks, as you choosing the class in runtime
ElasticsearchRepository[_, String].save require existential type _2 to be passed to the save method, so _1 doesn't fit
Possible solution:
repository.asInstanceOf[ElasticsearchRepository[Any, String]].save(getObject(t).asInstanceOf[Any]) //getClass will work with runtime class instead of Any, so should be fine
Another solution (saving existential type):
def getObject[T](t : T) = {
objectMapper.readValue(objectMapper.writeValueAsString(t), getClazz(t)).asInstanceOf[T]
} //assuming T is an existential - it will return same existential as you passed

Dynamically pass Type to Method<T>

I've a method , that retrieves to me some data according to some type I passed in parameter, like this :
protected void FillList<TEntity>()
{
doWorkForTEntity();
}
I Need to dynamically call this method :
Type[] entities = System.Reflection.Assembly.GetAssembly(typeof(User)).GetTypes();
Type currentEntity = (from entity in entities
where entity.Name.Equals(this.targetEntity)
select entity).FirstOrDefault();
FillList<currentEntity>();
I got this error :
The type or namespace name 'currentEntity' could not be found (are you missing a using directive or an assembly reference?)
I've tried an intermediate object type, no success
Any Idea please ?
Since there is no information about entity type in compile time, you need to construct and call appropriate method by reflection:
Type[] entities = System.Reflection.Assembly.GetAssembly(typeof(User)).GetTypes();
Type currentEntity = (from entity in entities
where entity.Name.Equals(this.targetEntity)
select entity).FirstOrDefault();
var method = this.GetType().GetMethod("FillList", BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(currentEntity);
method.Invoke(this, new object[0]);
You need to do that with reflection as well, so it won't fail in compile time (compiler checks):
Generic class:
Type[] entities = System.Reflection.Assembly.GetAssembly(typeof(User)).GetTypes();
Type currentEntity = (from entity in entities
where entity.Name.Equals(this.targetEntity)
select entity).FirstOrDefault();
Type fillListType= typeof(FillList<>);
Type constructedGenericClass = fillListType.MakeGenericType(currentEntity);
object myList = Activator.CreateInstance(constructedGenericClass );
Generic Method:
Type[] entities = System.Reflection.Assembly.GetAssembly(typeof(User)).GetTypes();
Type currentEntity = (from entity in entities
where entity.Name.Equals(this.targetEntity)
select entity).FirstOrDefault();
MethodInfo methodinfo = this.GetType().GetMethod("FillList");
MethodInfo genericMethod = method.MakeGenericMethod(currentEntity);
genericMethod.Invoke(this, null);
Type parameters must be specified at compile time and can´t be assigned at runtime like in your example. You get the error message because there´s no Type called currentEntiry since it´s just a variable.
Change your method to take an instance of the Type TEntity:
protected void FillList<TEntity>(TEntity instance)
{
doWorkForTEntity();
}
Create a dynamic instance from the Type name and then call the modified method:
dynamic instance = Activator.CreateInstance(this.targetEntity);
FillList(instance);
The dynamic type is basically doing what the other answers have shown you - but IMHO this code is neater and clearer in its intent.

Resources