blob: 625f89463adbec2b85f6e4cc5e3aad053fdb2a15 [file] [log] [blame]
//////////////////////
* Copyright (c) 2007-2012, Niclas Hedhman. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
//////////////////////
[[core-api-mixin,Mixin]]
= Mixin =
Mixins are the state-carrying part of a Composite instance. The other Fragments can not retain state between method
invocations as they are shared across Composite instances.
== Mixin Type ==
The Mixin Type is the interface that declares the Mixin methods. Each Mixin implementation (the classes defined in
the @Mixins annotation of a Composite declaration) implements one or more methods from one or more Mixin Types.
Mixin Type can be very simple, like;
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/BankAccount.java
tag=mixinType
-----------
Or contain hundreds of methods, subclassed from dozens of super interfaces.
The Mixin Types of a Composite are ;
* all the aggregated interfaces of the Composite Type, minus Composite meta-type interfaces, and
* all private mixin referenced types.
There is not a 1:1 correlation between Mixin Type and Mixin implementation. One can't even know if there are more or
less of one over the other. That is because a Mixin implementation can implement less than one, one, or more than one
Mixin Type.
It is also entirely possible that multiple implementation methods exists for a Mixin Type method. The mixin method
resolution algorithm will provide a deterministic behavior of which implementation of a method is chosen. The algorithm
is as follows;
For each declared method of all Mixin Types of a Composite;
* Iterate all Mixin types declared from left to right in the declaration,
* Iterate all Mixin types of super-interfaces from left to right in the 'extends' clause,
* Iterate all Mixin types within one interface before succeeding to the next interface,
* Iterate all super-interface Mixin types before proceeding to the super-interfaces of those,
* Iterate all Typed Mixin implementations of all super-interfaces, before repeating the algorithm for Generic Mixin
implementations,
This means that one Mixin implementation can 'override' a single method that a larger mixin implementation implements
together with many other methods. So, just because a mixin implements MixinTypeA.method1() and has an implementation
of MixinTypeA.method2(), doesn't mean that method2() is mapped to that mixin. This is very important to remember. The
Envisage tool is capable of visualizing how Mixin Type methods are mapped to implementations.
== Public Mixins ==
Mixins are the state holders of the composite instance. Public Mixins are the mixins that are exposed to the outside
world via the CompositeType interface.
*Each method in the CompositeType interface MUST be backed by a mixin class.*
Mixins are declared as annotations on the composite interface.
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/Something.java
tag=something
-----------
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/SomethingMixin.java
tag=something
-----------
In the above sample, the SomethingMixin will be made part of the Something composite.
If we have many interfaces defining many methods, that all must be backed by a mixin implementation, we simply list all
the mixins required.
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/Car.java
tag=mixin
-----------
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/Startable.java
tag=mixin
-----------
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/Vehicle.java
tag=mixin
-----------
In the example above, the VehicleMixin would need to deal with all methods defined in the Vehicle interface. That
interface could be very large, and could be totally independent concerns. So, instead we should use abstract mixins,
which are ordinary mixins but are lacking some methods. This is simply done by declaring the class abstract.
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/partial/Car.java
tag=partial
-----------
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/partial/Vehicle.java
tag=partial
-----------
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/partial/SpeedLocation.java
tag=partial
-----------
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/partial/SpeedMixin.java
tag=partial
-----------
Above the SpeedMixin only implements the accelerate() method, and Zest™ will only map that method to this mixin. The
other method of the SpeedLocation interface is not satisfied as the example is written and will generate a runtime
exception.
== Private Mixins ==
Public mixins expose their methods in the composite interface, and this is not always desirable. Zest™ supports
_Private Mixins_, which are only visible within the composite itself. That means that other fragments in the composite
can see/use it, but it is not visible to the clients of the composite.
Private Mixins are handled automatically. When Zest™ detects a +@This+ annotation referring to a type that is not defined
in the Composite interface, then that is a Private Mixin. The Mixin implementation class, however, must exist in the
list of Mixins in the @Mixins annotation. But often, the Private Mixin only list internal Property methods in the Mixin
Type, which will be satisfied by the standard PropertyMixin and hence always available.
This is particularly useful in Domain Driven Design, where you only want to expose domain methods, which are defined by
the context where they are used. But the state of the Mixin should not be exposed out at all. For instance, if we have
the Cargo interface like;
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/privateMixin/Cargo.java
tag=private
-----------
The interface is defined by its context, and not really exposing the internal state. So in the implementation we
probably do something like;
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/privateMixin/CargoMixin.java
tag=private
-----------
[snippet,java]
-----------
source=core/api/src/test/java/org/qi4j/api/mixin/privateMixin/CargoState.java
tag=private
-----------
So, in this typical case, we don't need to declare the Mixin for the CargoState, as it only defines Property methods,
which are handled by the standard PropertyMixin always present.
== Typed Mixin vs Generic Mixin implementations ==
Mixins, Concerns and SideEffects can either be "typed" or "generic". A Typed Mixin implementation implements one or
more Mixin Type interfaces, and one or more of the methods of those interfaces. A Generic Mixin implementation
implements java.lang.reflect.InvocationHandler, and can therefor be matched to any method of any interface.
Typically, AppliesTo annotation is used to filter the methods that such Generic Mixin implementation is mapped against,
and sometimes Generic Mixin implementations are "last resort".
Experience shows that Generic Mixin implementations are rare, and should only be used in extreme cases. They are
less frequent than Generic Concern or Generic SideEffect implementations, but inside the Zest™ API are a couple of
Generic Mixin implementations that are always present to make the life of the developer easier, such as PropertyMixin,
AssociationMixin, ManyAssociationMixin, NoopMixin. The first 3 are declared on the Composite and EntityComposite
interfaces and automatically included if needed. They also serve as excellent example of what they can be used for.
[snippet,java]
-----------
source=core/api/src/main/java/org/qi4j/api/property/PropertyMixin.java
tag=actual
-----------
Other examples that we have come across;
* Mapping from Property<type> to POJO style "properties".
* Remote Service delegation.
* Scripting delegation, where a script will implement the Mixin Type.
which seems to indicate that Generic Mixin implementations are likely to be used in integration of other technologies.
Typed Mixin implementations are much preferred in general business logic, as they will be first-class citizens of
the IDE as well, for navigation, find usage, refactoring and many other common tasks. This is one of the main
advantages of the Zest™ way of doing AOP compared to AspectJ et al, where "weaving" is something bolted onto an
application's classes via regular expressions and known naming conventions, which can change in an instance by a
developer being unaware of which PointCuts applies to his code.