Иногда сторонняя библиотека содержит API, которые возвращают закрытые классы, на которые вы не можете ссылаться напрямую. Одним из таких примеров является org.apache.avro.generic.GenericRecord.get(), который иногда может возвращать объект java.nio.HeapByteBuffer. Если бы я захотел переключить этот класс, я получу ошибку компиляции:
Object recordValue = genericRecord.get(someField);
switch (actualValue) {
case String avroString -> {
// do logic
}
case HeapByteBuffer avroBuffer -> {
// do logic
}
default -> log.warn("Unknown type");
}
Если вместо этого я попытаюсь использовать расширяющий класс, код скомпилируется, но зарегистрирует предупреждающее сообщение «Неизвестный тип»:
Object recordValue = genericRecord.get(someField);
switch (actualValue) {
case String avroString -> {
// do logic
}
case ByteBuffer avroBuffer -> {
// do logic
}
default -> log.warn("Unknown type");
}
Как я могу использовать расширенный переключатель для частного класса?
@ThomasKläger Я имел в виду, что вызывается строка log.warn(). Т.е. Дело обходит стороной ByteBuffer.
@JimGarrison Я не понимаю, что вы имеете в виду, когда говорите, что HeapByteBuffer создается на основе шаблона. Это часть JDK, и она была такой уже долгое время. Сегодня в мире JDK21+ это даже явно разрешено в закрытой иерархии. Я не думаю, что обновление JDK избавит от этого... Кроме того, меня не волнует, что это HeapByteBuffer. Это именно то, что мне дает Avro. Я совершенно счастлив относиться к этому как к ByteBuffer, если это все, что у меня есть. Если у вас есть ответ о том, как использовать HeapByteBuffer или лучший способ решения этой проблемы, чем я уже публиковал, я буду рад его услышать!
Ну, у меня есть Javadoc JDK20, и он не содержит HeapByteBuffer. Где вы видите Javadoc для этого класса?
case ByteBuffer b по сути является просто проверкой instanceof. Итак, если вы используете java.nio.ByteBuffer, а объектом является java.nio.HeapByteBuffer, то будет выполнен этот случай, а не вариант по умолчанию. Если ваш код не работает таким образом, я предлагаю вам отредактировать свой вопрос, чтобы предоставить минимально воспроизводимый пример.
«Я не понимаю, что вы имеете в виду, когда говорите, что HeapByteBuffer создается на основе шаблона». Это просто означает, что большинство подтипов Buffer на самом деле не существуют в виде исходных файлов в репозитории OpenJDK. Они генерируются из *.template файлов (см. здесь) перед компиляцией. И все конкретные реализации являются частными для пакета. Но это не имеет отношения к вашему вопросу, кроме того, что java.nio.HeapByteBuffer не доступен напрямую и является деталью реализации.
HeapByteBuffer является подклассом ByteBuffer (и всегда было так, начиная с Java 1.4), и поэтому ваш оператор log никогда не должен выполняться. Возможно, ваша реальная проблема заключается в том, что, извлекая поле из avro с помощью Object recordValue = genericRecord.get(someField);, вы на самом деле обрабатываете какое-то другое значение actualValue с неясной связью с извлеченным значением.
Помимо исправления использования фактического значения вместо RecordValue, может помочь дополнительное ведение журналов, например log.warn("Unknown type "+actualValue+" cls = "+actualValue.getClass()).




Второй пример в моем оригинальном ответе работает нормально. Не знаю, что я делал, чтобы нажать log.warn() раньше:
Object recordValue = genericRecord.get(someField);
switch (actualValue) {
case String avroString -> {
// do logic
}
case ByteBuffer avroBuffer -> {
// do logic
}
default -> log.warn("Unknown type");
}
Вы не ответили на ключевой комментарий, а именно: какую ошибку вы получаете? Потому что ваш исходный код (например, код в вашем вопросе, а не в этом ответе) отлично работает для всех, кроме вас, очевидно. Какое предупреждение вы получите? Возможно, у вас есть инструмент проверки или IDE, который добавляет предупреждения, и вы настроили его так, чтобы он предупреждал о глупых вещах, или он сломан. Мы не сможем помочь, если вы не сообщите нам, какие дополнительные линтеры/компиляторы вы используете; включение точного текста предупреждения может означать, что кто-то знает, какой инструмент линтера вы неправильно настроили.
@rzwitserloot Я отредактировал ответ, чтобы было более понятно, что предупреждение, о котором я имел в виду, было строкой log.warn(), которая вызывается, когда recordValue является HeapByteBuffer...
Смотрите мой ответ. Вы этого не понимаете. Этот обходной путь бесполезен.
Вы действуете в условиях серьезных недоразумений. Вот тривиальный пример, показывающий, что ваша мысленная модель происходящего здесь просто неверна:
class Test {
public static void main(String[] args) {
Object i = Integer.valueOf(42);
switch (i) {
case Number n -> System.out.println("N: " + n.intValue());
default -> System.out.println("NaN");
}
}
}
Это печатает N: 42.
Другими словами, ваша теория о том, что вы должны назвать точный, точный тип, которым является эта вещь, просто неверна — вы можете вставить супертип в оператор case, и он отлично сработает. Ваш «обходной путь» написания case Object i when i instanceof ByteBuffer — это глупый способ писать case ByteBuffer b.
Если вы наблюдаете за срабатыванием кейса default, то либо [A] вы не компилируете/запускаете код, который, по вашему мнению, у вас есть, либо [B] HeapByteBuffer не является ByteBuffer, и ваш case Object i when i instanceof ByteBuffer тоже не будет работать, потому что это не так. t байтовый буфер.
Класс
HeapByteBuffer, похоже, создан на основе шаблона и даже не существует как исходный файл в исходном коде JDK. Вы не можете эффективно ссылаться ни на что внутри него, кроме как наByteBuffer, и ваш код может сломаться при любом обновлении JDK. Что именно вы намерены делать там, где у вас есть// do logicнеобходимоеHeapByteBuffer? Если все, что вам нужно, — это избежать предупреждения, какое предупреждение вы увидите?