Interface Instantiator
Callers may use hasProduced(Object) to check whether a configuration object came from this instantiator.
Implementing
Implementing this interface correctly requires a number of considerations. It is recommended to check the library source code as a reference implementation.
Generated code must handle bridge and synthetic methods of its own accord. Users of this interface, like users of
MethodMirror, are expected to be externally ignorant of bridge and synthetic methods, insofar as caller code
will look identical regardless of the presence of bridge and synthetic methods.
Equality
An Instantiator is supposed to implement equality among instances produced by it. Instances produced by
other Instantiator implementations should never be equal to instances produced by this one. Each generating
method describes the equality considerations which must be upheld.
Notably, all methods must consider the leading iface parameter in calculating equality. The iface
identifies the interface being implemented, and if this interface differs between instances produced by this
instantiator, then those instances cannot be equal. This holds true not only for instances produced by the same
generating method, but also for equality between instances from different generating methods.
Because of the reflexive property of equals, generated instances may need to be aware of each others'
equality contracts even if they are produced by different generating methods. Additionally, hashCode must
be implemented in a manner compatible with the equality contract.
-
Method Summary
Modifier and TypeMethodDescription<I> @NonNull Igenerate(@NonNull Class<I> iface, @NonNull MethodYield methodYield) Generates the target class.<I> @NonNull IgenerateEmpty(@NonNull Class<I> iface) Generates an "empty" implementation for the given interface type, which lets the caller use its default method implementations.<I> @NonNull ReloadShell<I> generateShell(@NonNull Class<I> iface) Makes a reloadable shell for the given interface type.booleanhasProduced(@NonNull Object instance) Checks whether this instantiator produced the specified object.
-
Method Details
-
hasProduced
Checks whether this instantiator produced the specified object.All instantiators are required to mark the instances they generate using some unique method. This could be as simple as implementing a local interface as a marker.
- Parameters:
instance- the object- Returns:
- true if this instantiator produced it, false otherwise
-
generate
Generates the target class.Speaking logically, this function takes a map of methods to return values, and generates an implementation of the requested interface which, when its methods are called, yields the preconfigured values. This function is therefore an important backbone of the whole library, and the generated instance should operate as performantly as feasible.
Methods and Values
The implementor can use
MethodYield.entries()to traverse the methods ofiface, retrieving return values for each. EveryMethodYield.Entry.method()identifies a method belonging to theifaceargument, or one of its supertypes. These methods are guaranteed to represent the lowest in the class hierarchy, and they exclude overidden parent methods. In other words, parent methods which are overidden won't be provided; usingMethodYield.Entry.implementable()will return the overriding interface.Equality
Calling this function with equal
ifaceandmethodYieldparameters should yield equal instances. That is to say, an instance is equal to another if it has the same behavior (yields the same values, and calls the same default methods).Additionally, an instance should be considered equal to an instance produced by
generateEmptyif theMethodYieldpassed here is empty of preset values (seegenerateEmpty(Class)). For a shell instance produced bygenerateShell, please seegenerateShell(Class).- Parameters:
iface- the interface to implementmethodYield- a map of methods to the values they are to yield, for each type in the hierarchy ofiface- Returns:
- the generated implementation
-
generateShell
Makes a reloadable shell for the given interface type.Equality
The returned
ReloadShellitself should use identity equality (only be equal to itself). However, the shell instance (fromReloadShell.getShell()) should have the following equality behavior.First, it requires other instances to have the same
ifaceargument to be considered equal. This holds true not only for shell instances produced by this method, but also instances produced bygenerateandgenerateEmpty.Secondly, the delegate should be considered. Two shell instances are equal if they have equal delegates, including potentially null delegates (null equals null). Otherwise, the delegate must be nonnull, and the shell instance should evaluate its own equality by checking if the current delegate is equal (by calling its
equalsmethod).- Type Parameters:
I- the interface type- Parameters:
iface- the interface to implement- Returns:
- a reload shell
-
generateEmpty
Generates an "empty" implementation for the given interface type, which lets the caller use its default method implementations.The purpose of this function is for the caller to use the default methods of the provided interface, and the caller promises not to use non-default methods. If that promise is broken, behavior is not defined.
Equality
Calling this function with the same
ifaceparameter should yield equal instances.The instance should also be considered equal to an instance produced by
generate(Class, MethodYield), if and only if the interfaces match and theMethodYieldprovided to that function is empty of preset values (i.e., excluding the special valueInvokeDefaultFunction.) That is to say, an "empty" instance being generated by this method can only be equal to an instance generated by the other method, if the other instance implements the same interface and only invokes default method implementations.For a shell instance produced by
generateShell(Class), please see- Type Parameters:
I- the interface type- Parameters:
iface- the interface to implement- Returns:
- the instance
-