MatchableBinding.java
/*
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.jersey.inject.weld.internal.inject;
import org.glassfish.jersey.internal.inject.Binding;
import java.lang.reflect.Type;
import java.util.Set;
/**
* A Binding to be able to be compared and matched in the runtime to be properly initialized.
*
* @param <T> Type of the bean described by this injection binding.
* @param <D> Concrete injection binding implementation type.
*/
public abstract class MatchableBinding<T, D extends MatchableBinding> extends Binding<T, D> {
protected abstract MatchLevel bestMatchLevel();
protected Matching<D> matches(Binding<?, ?> other) {
final Matching<D> matching = matchesContracts(other);
if (matching.matchLevel == MatchLevel.FULL_CONTRACT) {
if (getImplementationType().equals(other.getImplementationType())) {
matching.matchLevel = MatchLevel.IMPLEMENTATION;
}
}
return matching;
}
/**
* Return a Matching object that represents comparison between contracts of this binding and a given binding.
* The result contains a reference to this binding.
* @param other
* @return
*/
public Matching<D> matchesContracts(Binding<?, ?> other) {
boolean atLeastOneMatch = false;
boolean allMatch = true;
final Set<Type> firstContracts = getContracts();
final Set<Type> secondContracts = other.getContracts();
final Set<Type> biggerContracts = firstContracts.size() < secondContracts.size() ? secondContracts : firstContracts;
final Set<Type> smallerContracts = firstContracts.size() < secondContracts.size() ? firstContracts : secondContracts;
for (Type thisType : biggerContracts) {
boolean aMatch = false;
for (Type otherType : smallerContracts) {
if (thisType.equals(otherType)) {
aMatch = true;
atLeastOneMatch = true;
break;
}
}
if (!aMatch) {
allMatch = false;
}
}
final MatchLevel matchLevel = atLeastOneMatch
? (allMatch ? MatchLevel.FULL_CONTRACT : MatchLevel.PARTIAL_CONTRACT)
: MatchLevel.NONE;
final Matching<D> matching = new Matching<>((D) this, matchLevel);
return matching;
}
/**
* Matching object that represents the level of a match between two bindings. Contains a reference to a MatchableBinding
* whose instance was used to create the Matching object.
* @param <D> Concrete injection binding implementation type.
*/
public static class Matching<D extends MatchableBinding> implements Comparable<Matching> {
private D binding;
protected MatchLevel matchLevel;
public static <D extends MatchableBinding> Matching<D> noneMatching() {
return new Matching<D>(null, MatchLevel.NONE);
}
protected Matching(D binding, MatchLevel matchLevel) {
this.binding = binding;
this.matchLevel = matchLevel;
}
@Override
public int compareTo(Matching other) {
return other.matchLevel.level - this.matchLevel.level;
}
public Matching better(Matching other) {
return compareTo(other) <= 0 ? this : other;
}
public boolean isBest() {
return matches() && matchLevel == binding.bestMatchLevel();
}
public boolean matches() {
return matchLevel.level > MatchLevel.NONE.level;
}
public D getBinding() {
return binding;
}
}
/**
* Internal granularity of a Matching.
*/
protected static enum MatchLevel {
NONE(0),
PARTIAL_CONTRACT(1),
FULL_CONTRACT(2),
IMPLEMENTATION(3),
SUPPLIER(4);
private final int level;
MatchLevel(int level) {
this.level = level;
}
}
}