How does component instantiation work with respect to scope type - seam

Even though I have specified the scope type as method, it gets instantiated in CONVERSATION scope.
>
UserHome userHome = (UserHome) Component.getInstance(UserHome.class, ScopeType.METHOD);
This is quite confusing, can someone explain this behavior?

When you call
Component.getInstance(UserHome.class, ScopeType.METHOD);
Seam internal behavior is to call
Object result = Contexts.lookupInStatefulContexts(name);
lookupInStatefulContexts API says
Search for a named attribute in all contexts, in the following order: method, event, page, conversation, session, business process, application.
As your ScopeType.METHOD does not contain your UserHome.class component, The search go on until get its scope (StypeType.CONVERSATION, right ?)
UPDATE
I was under the impression that if you specify the ScopeType to getInstance method you will be able to create the object within that scope
If the target component does not have the desired scope associated, getInstance method does not create the component within that scope. Instead it performs a hierarchical search by using Contexts.lookupInStatefulContexts till get some assigned scope
If you want more than one scope can be assigned to a component, you must scecify it by using #Role (#Roles) annotation
#Name("user")
#Scope(ScopeType.EVENT)
#Role(name="loggedUser", scope=ScopeType.SESSION)
public class User { ... }
So you specify the desired scope
Component.getInstance(User.class, ScopeType.EVENT);
or
Component.getInstance(User.class, ScopeType.SESSION);
remember Seam performs lookup by field/property name
private #In User user; // Take ScopeType.EVENT as scope
private #In User loggedUser; // Take ScopeType.SESSION as scope

I assume your UserHome class extends Seam's EntityHome class. The super class of EntityHome, which is Home, is in scope ScopeType.CONVERSATION:
#Scope(ScopeType.CONVERSATION)
public abstract class Home<T, E> extends MutableController<T>
Either you did not override the scope in your UserHome declaration or Seam ignores #Scope annotations in subclasses if one of the super classes already have an #Scope annotation.

Related

Dart - Casting List<SuperType> to List<SubType> using generics

I am new to Flutter and Dart, coming from native Android.
Android has a very nice database abstraction architecture called the Room Persistence Library. As far as I am aware, no such database abstraction architecture exists for Flutter using the MVVM / MVC design patterns.
My solution was to create a Dart version of it myself. I got it pretty much done after a few headaches, but I cannot seem to get LiveData to work properly using generics.
I set up my class like this:
class LiveData<T> {
...
}
Now when I want to return some data, it can either be an Object or List<Object>. I found a neat hack for differentiating the two from T:
...
// Parse response
// This checks if the type is an instance of a single entity or a list.
if (entity is T) {
cachedData = rawData.isEmpty ? null : entity.fromMap(rawData.first) as T;
} else {
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
}
...
The problem lies in the second block:
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
With the error:
- Unhandled Exception: type 'List<Entity>' is not a subtype of type 'List<Vehicle>' in type cast
The question then becomes: How can I cast Entity to Vehicle when I do not have access to the Vehicle class. Only an instance of it is assigned to an Entity entity variable.
Here's a snippet to demonstrate my access to Vehicle:
final Entity entity;
...assign Vehicle instance to entity...
print(entity is Vehicle) // True
I've tried using .runtimeType to no avail. I have also thought about splitting LiveData into two classes, the second one being LiveDataList. Although this seems to be the easiest solution to not bug the code- it would bug me (bad pun is intentional) and break the otherwise pretty direct port of Room.
As a temporary solution, I have abstracted out the build logic into a generic function to be passed to the LiveData in the constructor.
final T Function(List<Map<String, dynamic>> rawData) builder;
And now I call that instead of the previous code to build the cachedData.
// Parse response
cachedData = builder(rawData);
With the constructor for the LiveData<List<Vehicle>> called when accessing all vehicles in the Dao<Vehicle> being:
class VehicleDao implements Dao<Vehicle> {
...
static LiveData<List<Vehicle>> get() {
return LiveData<List<Vehicle>>(
...
(rawData) => rawData.map((e) => Vehicle.fromMap(e)).toList(),
...
);
}
}
In Dart (and indeed in many languages) generics screws with the concept of inheritance. You would think that if Bar inherits from Foo, that List<Bar> would also be castable to List<Foo>.
This is not actually going to be the case because of how generics work. When you have a generic class, every time you use that class with a different type, that type is treated as a completely separate class. This is because when the compiler compiles those types, class MyGenericType<Foo> extends BaseClass and class MyGenericType<Bar> extends BaseClass are basically converted to something like class MyGenericType_Foo extends BaseClass and class MyGenericType_Bar extends BaseClass.
Do you see the problem? MyGenericType_Foo and MyGenericType_Bar are not descendants of one another. They are siblings of each other, both extending from BaseClass. This is why when you try to convert a List<Entity> to List<Vehicle>, the cast doesn't work because they are sibling types, not a supertype and subtype.
With all this being said, while you cannot directly cast one generic type to another based on the relationship of the generic type parameter, in the case of List there is a way to convert one List type to another: the cast method.
List<Entity> entityList = <Entity>[...];
List<Vehicle> vehicleList = entityList.cast<Vehicle>(); // This cast will work
One thing to note though, if you are casting from a supertype generic to a sub-type generic and not all the elements of the list are that new type, this cast will throw an error.

netcore DI container returns different instances for same registration with overloads

I encountered a Problem with the DI framework of netcore. I am aware about the different ways to register an type in the DI container.
Specifically I am interested in the .AddSingleton method. There are many overlaods of this method.
My Problem is that I want to ensure that when I register the same class in different ways (with an interface and just with the class type), then two instances are created, one for each "registration" way.
Lets say I have an Interface called ISomeInterface an one implementation of it named ImplementationOfSomeInterface.
In my case I want the DI system to create an instance whenever the ImplementationOfSomeInterface is requested. Further I have some places where I define the dependency just with the interface ISomeInterface.
The Problem is that the DI system returns 2 instances of ImplementationOfSomeInterface. One for the case where the dependency is related of the class and one for the case where the dependency is given by the Interface.
I already checked many documentation and tutorials, but they all just explain the differences of AddSingleton, AddScoped etc...
// registration with the class type
services.AddSingleton<ImplementationOfSomeInterface>()
//registration with an interface and the corresponding 'same' class type
services.AddSingleton<ISomeInterface, ImplementationOfSomeInterface>();
//--------- now the usage of it -------------------
public TestClassA(SomeInterfaceImplementation instance)
{
var resultingInstA = instance;
}
public TestClassB(ISomeInterface instance)
{
var resultingInstB = instance;
}
//I would expect that resultingInstA is pointing to the very same object of
//resultingInstB => but they are different!
I would expect that resultingInstA is pointing to the very same object of resultingInstB => but they are different!
How can I achieve that I get the same instance back?
You can do it by registering an instance of the class rather than just the type.
var instance = new ImplementationOfSomeInterface();
services.AddSingleton(instance);
services.AddSingleton<ISomeInterface>(instance);
Now any attempt to resolve ImplementationOfSomeInterface or ISomeInterface will both return the instance initialized here.

Prevent autoloading for abstract controller in symfony

I have an abstract controller which has a function getStatusAction to render a status based on the entity which will come as parameter.
abstract class HumanController extends CRUDController
{
public function getStatusAction(Human $human)
{
// return new Response ...
}
}
Human is an entity class but also abstract. One child is for example man.
So i create a ManController
class ManController extends HumanController
{
}
If i now call in my twig template the getStatusAction with something like
{{ path('path_to_man_controller_status_action', {'human' : '12'}) }}
An error occurs, because some mechanism tries to guess that my parameter is a human which is an abstract class. But this cannot be instantiated.
The provided class Human is abstract, and can not be instantiated
Instead i want that the mechanism should load the entity from my concrete class, in this case Man.
Yes, the framework can't know what class is meant, but how to solve this? I want to have one central function which is doing something with all my entities which are childs of the Human class. I don't want to write the getStatusAction function over and over again in my child classes.
So, is it at least possible to overwrite the abstract class function definition (with getStatusAction(Man $man)) but keep the implementation of the original class?
If not, is it possible to turn off the symfony automatic entity loading mechanism to pass just the entities trough my function?
Some other smart ideas? Thanks.

Access objects instantiated in Flex app's MXML file in other AS classes

I've got an object declared and instantiated in my Flex application's singular MXML file:
public var CDN:CDNClass = new CDNClass;
I would like to access this same CDN object (and its public methods and properties) in another class declared in a separate .as file as such:
package my.vp
{
import my.media.CDNClass;
public class SyncConnectorManager
{
private function syncMessageReceived(p_evt:SyncSwfEvent):void
{
switch (p_evt.data.msgNm)
{
case "startStream" :
// Play a stream
CDN.parsePlayList(p_evt.data.msgVal);
break;
But when I try to access the public method parsePlayList in the CDN object in a method in the class defined in the .as file, I get the following error:
Access of undefined property CDN
The reason I want to do this is to break up the logic of my application into multiple AS files and have minimal MXML files, probably only one.
Thanks - any help is much appreciated. Perhaps my OOD/OOP thinking is not correct here?
IT depends on your class architecture. For your code to work, the CDNClass instance must be defined and implemented inside your SyncConnectorManager.
Generally, you can always call down into components, but should never call up
One option is to pass the instance ofCDNClass to a variable inside SyncConnectorManager. Add this variable to your SyncConnectionManager class:
public var CDN:CDNClass = new CDNClass;
And at some point do this:
syncConnectorManagerInstance.CDN = CDN;
That way both classes will have access to the same CDN instance and can call methods on it.
Yes, your OOP thinking is not correct here. You should take in mind differences between classes and instances. This line declares a filed in a current class and initiates it with an instance:
public var CDN:CDNClass = new CDNClass;
So current instance of your MXML class (you can think about it as usual AS class with some other notation) has public field. To operate with CDN instance you need something from the following:
Read the value of CDN (as far as it is public) from the instance of your MXML class. You need some reference to it for that.
The instance of your MXML class can have a reference to the instance of SyncConnectorManager and SyncConnectorManager should have a way to inject the value of CDN there. Something like:
Your class:
package my.vp
{
import my.media.CDNClass;
public class SyncConnectorManager
{
private var CDN:CDNClass;
public function SyncConnectorManager(CDN:CDNClass)
{
this.CDN = CDN;
}
private function syncMessageReceived(p_evt:SyncSwfEvent):void
{
switch (p_evt.data.msgNm)
{
case "startStream" :
// Play a stream
CDN.parsePlayList(p_evt.data.msgVal);
break;
In your case SyncConnectorManager class hasn't CDN declared (the problem of the compiler error you mentioned) and instantiated (the problem of NPE even if you just declare field).
As the bottom line I can suggest you to follow ActionScript naming and coding conventions to talk other people and team members about your code :)

Why does injection fail when I dont provide an 'id' in the following flex/parsley code?

MXML snippet -
<startup:MyTasks autoStart="false" >
<startup:tasks>
<startup:ATask id="aTask" />
<startup:BTask id="bTask" />
</startup:tasks>
</startup:MyTasks>
<Object type="{ MyViewPM }" id="someID"/>
ATask -
public class ATask extends Task
{
[Inject]
public var viewPM : MyViewPM;
}
MyTasks is based on http://code.google.com/p/rojored/source/detail?r=4b0a2dc267
If I leave out the 'id' of the 2 tasks (ATask, BTask), the property of these tasks dont get injected and are null.
Does parsley require ids on the objects to manage them?
It might not be that intuitive but the MXML syntax you're using creates a
MyTask object in you context and creates and array with tasks that it assigns
to the property "tasks" of MyTask, not of the context itself. It might help
to think of it as:
myContext.myTasks.tasks = [aTask, bTask];
When parsley introspects myContext, it will find myTasks and will process it.
It won't find aTask or bTask which are nested inside the tasks array in
myTasks.
In Flex MXML, when you set an id to a tag it then becomes a property of the
class in which it is being instantiated---in this case, the nested ATask and
BTask will become properties of the context in which you are declaring them.
So it will be more like:
myContext.myTasks.tasks = [aTask, bTask];
myContext.aTask = aTask;
myContext.bTask = bTask;
... So only then, when Parsley loops through the properties of your context,
will it find the nested tasks as well and will be able to process them.
I know MyTask doesn't have that myTask id, but it doesn't need it as it is a direct property of the context (so the automatically generated property name is enough). If you were to take out TaskA and TaskB out of the MyTask definition and put them out at the same level as MyTask you'll see that the PM is properly injected into them but, of course, they won't work on the queue as you need them to.
HTH,
Gabriel

Resources