io.micronaut.pulsar.processor.DefaultSchemaHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of micronaut-pulsar Show documentation
Show all versions of micronaut-pulsar Show documentation
Integration between Micronaut and Apache Pulsar
The newest version!
/*
* Copyright 2017-2022 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.pulsar.processor;
import io.micronaut.context.BeanContext;
import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.type.Argument;
import io.micronaut.inject.qualifiers.Qualifiers;
import io.micronaut.messaging.exceptions.MessageListenerException;
import io.micronaut.pulsar.MessageSchema;
import io.micronaut.pulsar.schemas.SchemaResolver;
import jakarta.inject.Singleton;
import org.apache.pulsar.client.api.Message;
import org.apache.pulsar.client.api.Schema;
import org.apache.pulsar.client.impl.schema.*;
import org.apache.pulsar.common.schema.KeyValueEncodingType;
/**
* Message type resolver for Pulsar schema. Simplifies resolving Java types to Pulsar schemas by using requested
* transmission type via annotations and injecting proper resolvers in place.
*
* @author Haris Secic
* @since 1.1.0
*/
@Singleton
public class DefaultSchemaHandler {
private final BeanContext context;
/**
* @param context BeanContext for fetching extra resolvers
* @since 1.1.0
*/
public DefaultSchemaHandler(final BeanContext context) {
this.context = context;
}
/**
* Resolve which schema to use for ser/der.
*
* @param body argument that represents message body
* @param key if message is of type key-value a key should be passed; otherwise use null
* @param topicAnnotation annotation corresponding to one of the Pulsar annotations: consumer, reader, producer.
* @param target name of the method, field, or other that represent where the error might be in case of it.
* @return new Schema
*/
public Schema> decideSchema(final Argument> body,
@Nullable final Argument> key,
final AnnotationValue> topicAnnotation,
final String target) {
final boolean isKeyValue = key != null;
final MessageSchema schema = topicAnnotation.getRequiredValue("schema", MessageSchema.class);
if (!isKeyValue) {
return resolve(schema, body, target);
}
final KeyValueEncodingType type = topicAnnotation.getRequiredValue(KeyValueEncodingType.class);
final Schema> bodyType = resolve(schema, body, target);
final Schema> keyType;
if (type == KeyValueEncodingType.INLINE) {
keyType = resolve(schema, key, target);
} else {
keyType = resolve(topicAnnotation.getRequiredValue("keySchema", MessageSchema.class), key, target);
}
return KeyValueSchemaImpl.of(bodyType, keyType, type);
}
private Schema> resolve(final MessageSchema schema, final Argument> argument, final String target) {
final Class> type = bodyType(argument);
if (MessageSchema.BYTES == schema && byte[].class != type) {
if (String.class == type) {
return StringSchema.utf8();
}
return context.getBean(SchemaResolver.class, Qualifiers.byName(MessageSchema.JSON.getSchemaResolverName()))
.forArgument(type); //default to JSON for now
}
return switch (schema) {
case BYTES -> BytesSchema.of();
case BYTEBUFFER -> ByteBufferSchema.of();
case INT8 -> ByteSchema.of();
case INT16 -> ShortSchema.of();
case INT32 -> IntSchema.of();
case INT64 -> LongSchema.of();
case BOOL -> BooleanSchema.of();
case FLOAT -> FloatSchema.of();
case DOUBLE -> DoubleSchema.of();
case DATE -> DateSchema.of();
case TIME -> TimeSchema.of();
case TIMESTAMP -> TimestampSchema.of();
case STRING -> StringSchema.utf8();
default -> {
try {
yield context.getBean(SchemaResolver.class, Qualifiers.byName(schema.getSchemaResolverName()))
.forArgument(type);
} catch (final MessageListenerException typeHandlingException) {
throw new MessageListenerException(typeHandlingException.getMessage() +
" (parameter: " + target + ")");
}
}
};
}
public static Class> bodyType(final Argument> body) {
if (Message.class.isAssignableFrom(body.getType())) {
return body.getTypeParameters()[0].getType();
}
return body.getType();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy