Когда вы пишете type(nameStartsWith("com.demo").or(is(Point.class)))
, вызов метода type
предоставляет контекст для метода or
, который обеспечивает контекст для метода is
.
Существует большая гибкость вAPI-интерфейс ByteBuddy использует преимущества того факта, что это сопоставители, поэтому сопоставитель, способный проверять экземпляры типа X, может также проверять экземпляры подтипов X.
Например, сигнатура метода
<T extends TypeDefinition> ElementMatcher.Junction<T> is(Type type)
позволяет вывести TypeDescription
для T
, который является подтипом TypeDefinition
.
Но также сигнатура
<U extends S> ElementMatcher.Junction<U> or(ElementMatcher<? super U> other);
позволяет вывести более конкретный тип U
расширяет оба типа соответствия, поэтому, если вы используете
ElementMatcher.Junction<NamedElement> a = nameStartsWith("com.demo");
ElementMatcher.Junction<TypeDefinition> b = is(Point.class);
var combined = a.or(b);
new AgentBuilder.Default().type(combined);
, компилятор может определить тип ElementMatcher.Junction<TypeDefinition>
как тип для combined
, тогда как сигнатура
void type(ElementMatcher<? super TypeDescription> typeMatcher)
будетпринять совпадение этого типа, так как TypeDefinition
является супертипом TypeDescription
.
В отличие от этого, когда вы создаете Stream
через
Stream.of(nameStartsWith("com.demo"), is(Point.class))
, существуетнет возможности использовать особый характер спичек;компилятор должен найти общий базовый тип для ElementMatcher.Junction<NamedElement>
и ElementMatcher.Junction<TypeDefinition>
, который в конечном итоге будет равен ElementMatcher.Junction<? extends NamedElement>
, поскольку NamedElement
является супертипом TypeDefinition
.
Затем, последующий reduce
пытается применить or
с подстановочным типом и, что еще хуже, для сигнатуры reduce(BinaryOperator<T>)
требуется функция, принимающая два ввода одного типа, возвращающая этот тип, поскольку она может быть снова передана в качестве ввода в функцию сокращения.Так что он не способен использовать ослабленную сигнатуру типа метода or
.
Если вы применяете более специфический тип для вызова метода nameStartsWith
, такой как
var typeSpec = Stream.of(
ElementMatchers.<TypeDefinition>nameStartsWith("com.demo"),
is(Point.class))
.reduce(ElementMatcher.Junction::or).orElseThrow();
new AgentBuilder.Default().type(typeSpec);
, он будетРабота.Он также будет работать при применении типа в потоке, например,
var typeSpec = Stream.<ElementMatcher.Junction<TypeDefinition>>of(
nameStartsWith("com.demo"),
is(Point.class))
.reduce(ElementMatcher.Junction::or).orElseThrow();
, поскольку тип вызова метода Stream.of
может использоваться для определения типов для вызова nameStartsWith
.
Как правило, типы могут распространяться через вложенные вызовы методов, но не через цепочечные вызовы, поэтому при использовании цепочки Stream.of(…).reduce()
функция, используемая в reduce
, не может помочь определить типы для вызова of
.