← back to UniJ README
Table of Contents:
Q: Why are there two APIs (User API and Service API) in UniJ?
A: So that:
-
for the user, we can exactly mirror the JDK API (equivalent class names, static methods), e.g.:
List.of()
⟷UniLists.of()
Collectors.toUnmodifiableList()
⟷UniCollectors.toUnmodifiableList()
-
for the service provider, we can expose an interface with all the related method to be implemented together, e.g.:
UnmodifiableListFactory.of()
UnmodifiableListFactory.collector()
Q:
What happens if multiple bindings of the same type are available at runtime
(e.g. pl.tlinkowski.unij.service.misc.jdk8
and pl.tlinkowski.unij.service.misc.jdk11
)?
A: If multiple bindings of the same type are present on the runtime classpath/modulepath, service implementations with the top priority (lowest number) will be selected.
In the example above,
Jdk11MiscellaneousApiProvider
(priority = 10) will be selected over
Jdk8MiscellaneousApiProvider
(priority = 40) for
MiscellaneousApiProvider
.
Q:
Why not simply use ArrayList
s
wrapped with
Collections.unmodifiableList
,
etc. instead of UniJ?
A:
You can do it if you find it convenient. To me, it's too verbose (low readability), and hence more error-prone.
Besides, it's not null-safe, not as efficient (UniJ's JDK 8 binding uses
Arrays.asList
instead of ArrayList
), and doesn't allow for easy migration once you upgrade to JDK 11+.
Q:
Why not depend on an external library providing immutable List
s instead of on UniJ (e.g.
Guava or Eclipse Collections)?
A: If you program to Guava's / Eclipse Colletions' proprietary APIs, you get rather far from the JDK 9+ API and its specification. Once you decide to upgrade to JDK 11+, migrating to JDK's collections will not be straightforward due to API differences.
Q: What to do about a dependency on UniJ once I migrate to JDK 11+?
A:
In such case, it's best to remove UniJ altogether (will be a simple matter of replacing all occurrences of UniLists
with List
, etc.). Alternatively (if you don't have time for that), you can just change your
UniJ bundle to
pl.tlinkowski.unij.bundle.jdk11
.
Q:
Why not simply use ArrayList
s
wrapped with
Collections.unmodifiableList
,
etc. instead of UniJ?
A:
See this end-user Q&A. Moreover, if your users themselves use JDK 9's,
Guava's or Eclipse's Collection
s:
- you'd waste potential by not using the best
Collection
implementations available - you'd introduce inconsistency regarding which
Collection
implementations are used in your users' app/library
Q:
Why not depend on an external library providing immutable List
s instead of on UniJ (e.g.
Guava or Eclipse Collections)?
A: See this end-user Q&A. Moreover, by bundling with an external library, you'd impose a heavy (potentially unwanted) dependency on your users. On the other hand, bundling with extremely lightweight UniJ API shouldn't cause any problems.
Q:
Why bother with a Collection
factory method facade (like UniJ) for a library?
A:
As a library maintainer, the choice of Collection
implementations shouldn't be yours. It's the same as with
logging — you shouldn't choose the logging backend, and should only program to a facade like
SLF4J. That's precisely what UniJ lets you do with respect to Collection
factory methods.
Q: How can I use UniJ in my library?
A: You can choose one of the below artifacts as a dependency for your library:
-
(recommended) UniJ User API (
pl.tlinkowski.unij.api
)-
pros: extremely lightweight (API only); no redundant dependencies
-
cons: your users must add a dependency on a UniJ bundle / bindings of their choosing
-
-
(alternative) UniJ JDK 8 bundle (
pl.tlinkowski.unij.bundle.jdk8
)-
pros: your users don't have to add a dependency on any UniJ bundle / bindings (they may do so to override the JDK 8 bindings, though)
-
cons: heavier than API only; may result in redundant dependencies if the user overrides some bindings
-
Here's what needs to be done by you and your users to use each option:
-
UniJ User API:
- you follow Usage for Library Providers
- you ask your users to follow Usage for End Users
-
UniJ JDK 8 bundle:
- you follow Basic Implementation Usage: Bundles
- you inform your users they may follow Usage for End Users
In both cases, your users may need to add certain external dependencies.
Q: How can I create a custom UniJ service implementation and provide it as a binding?
A: You can create a custom UniJ binding by:
-
adding proper dependencies to your project (see Usage for Custom Binding Providers)
-
implementing an interface from the Service API
-
annotating it with a special
@UniJService
annotation -
providing a
module-info.java
entry (for JDK 9+) and/or aMETA-INF
JAR entry (for JDK 8; I recommend Google's@AutoService
for it)
Example:
@UniJService(priority = 1)
@AutoService(UnmodifiableListFactory.class)
public class CustomUnmodifiableListFactory implements UnmodifiableListFactory {
// ...
}
You should also create the following Spock specification to ensure that your service implementation adheres to the UniJ specification:
class CustomUnmodifiableListFactorySpec extends UnmodifiableListFactorySpec {
def setupSpec() {
factory = new CustomUnmodifiableListFactory()
}
}
← back to UniJ README