Replacement of old, verbose and useless Adapter
project.
This project is intended to help adapter pattern implementation.
Adapter pattern is used to adapt a type to another without losing capabilities and remaining linked to instance.
For example, if you have 2 platforms, and each platform defines an type called Person
and you want to treat these types with same code:
public class Lib1_Person {
private final String name;
private final int age;
// ...
}
public class Lib2_Person {
private final String name;
private final int age;
private final List<Lib2_Person> parents;
// ...
}
public class PersonProcessor {
public void process(Lib1_Person person) {
// ...
}
public void process(Lib2_Person person) {
// ...
}
}
There are various ways to solve this problem:
- Destruct these instances and delegate call to another method. (good, as far you don't need to manipulate other properties and does not call it from many places)
- Process every type in a method. (Bad, too bad)
- Create a proxy and call methods of other type. (Works, is really good and time saver, but at the same time, is hard to maintain if the types have different signatures) Internally cached
- Creates an Adapter and cache or instantiate on every call. (Good, and the best way)
Example: See ReadmeExamples.java.
AdapterHelper provide utilities to working with the last approach and reducing the boilerplate code.
AdapterManager
is the class used to register, get and use adapters and converters. This class also provides a weak cache for Adapter instances.
The base class of all adapter classes, commonly adapter interfaces extend it and AdapterImplGen
generates the concrete implementation.
More simple adapter, this only have a original instance
property, this is commonly used in places where AdapterManager
does not have to be provided (simple adapters).
The converter of data types, like String
to Integer
.
Class used to store specification of Adapter
, this class is used for registration and internally used to fetch Adapter
s.
Utility class used to generate implementation of Adapter
interfaces (explained later).
Used to generate additional fields in implementations generated by AdapterImplGen
Used to store dynamical fields (alternative for @Field
)
Used to Strong cache adapter instances.
There are multiple ways to create adapters using AdapterHelper
utilities, the mostly used (at least by me), is the combination of interface adapter
and AdapterImplGen
, this keeps extensibility and you don't need to write concrete implementation, examples:
Converters are used to convert data types. Converted objects are not cached like Adapters
and does not have access to AdapterManager
because they should not access it. Converters are commonly singleton.
Example:
Sometimes you need to store additional data, but the field does not exists in target class, to solve this problem you can use @Field
annotation to include fields in your adapter generated class (using AdapterImplGen
) or add fields to your concrete adapter implementation (make sure to annotate your adapter with StrongCache
, I will explain it later). You can also use WeakAdapteeStorage
(or your own implementation of IStorage
) to store dynamic fields in a map.
StrongCache
is required because by default, AdapterManager
caches adapters weakly, this means that if it is not referenced in the code, it will be collected by the gc, this causes field values to be lost, to avoid this behavior, you should annotate your adapter class (or any interface or sub-class) with StrongCache
, but this should be used with care, because it will prevent GC from collecting references, which can lead to memory leaks, to remove adapters from cache you should use uncacheStrong
(or uncacheAllStrong
if you need to remove all adapters).
Obs: As Field
and Fields
are annotated with StrongCache
, all classes annotated with them will be strong cached
Also AdapterHelper have WeakAdapteeStorage
which can be used to store fields by adaptee
instance instead of storing in Adapter
class in fields, because of weak nature, if adaptee
is collected, all field values reference are lost.
Obs: WeakAdapteeStorage
class is not singleton, but have an GLOBAL
instance, and each AdapterManager
has its own Storage
instance, which is implemented by WeakAdapteeStorage
and is visible to use.
Example: DynamicFieldTest.java.
You are free to use concrete adapters and register them in AdapterManager
, if you have only concrete adapters, you don't need Kores, Kores-BytecodeWriter, KoresProxy nor KoresGenUtil.
Okay, it is not true anymore, there is no guarantee that AdapterHelper
works without Kores
, but I plan to separate the project in two modules, a basic module that does not require Kores
and a full module that requires. This is not true anymore because even if you don't have Kores
, the classes that depends on Kores
exists, some frameworks may not like that, and others projects may use these classes.
Provides collections which handles and delegates adaptation to a wrapped instance, this means that if you adapt OldPerson
to Person
and them create a List
of Person
from a List
of OldPerson
(using AdapterManager
), all changes made on both List
s will be reflected on each other.
Currently, we only implemented Collection
, List
, Set
and Map
. You can also open an issue to request more implementations or send a pull request of implementation of other classes (and we will accept happily). But we only accepts implementations on top of Java or Kotlin classes.