Spring Redis pubsub: onMessage message.getBody() does not convert to correct String - redis

I am trying to implement RedisSubscriber which implements MessageListener
#Override
public void onMessage(Message message, byte[] pattern) {
messageList.add(message.getBody().toString());
System.out.println("Message received: " + new String(message.getBody(), StandardCharsets.UTF_8));
}
But in my console it does not print the right string, it prints:
Message received: �� t Hi test
Why is it printing extra characters?
I tried deserializing it as well but it does not convert properly

I solved it. Just add String Serializer in RedisConfig
#Bean
open fun redisTemplate(): RedisTemplate<String, Any> {
val template = RedisTemplate<String, Any>()
template.setConnectionFactory(jedisConnectionFactory())
template.setDefaultSerializer(StringRedisSerializer())
return template
}

Related

Distinguish function from extension

I tried to write a funtion, which can be inserted in any expresion, in order to log the value:
val x = (2.debug() + 3.debug()).debug("2+3")
But instead I wrote the following endless loop:
fun debug (message: String) {
Log.d (R.string.app_name.toString(), message) }
fun <T> T.debug (tag: String = "value"): T {
debug ("$tag: $this")
return this
}
My aim was to write a "normal" function (1st) and an extension function (2nd) and the extension function should call the normal function.
The problem in my code is: the extension function calls itself instead of the normal function. I do not understand this, because I did not specify an instance receiver in the extension function.
How to fix this?
Given you have different param names in each function, you could change the second function to call the first one with named arguments:
fun <T> T.debug (tag: String = "value"): T {
debug (message = "$tag: $this")
return this
}
I couldn't find a way to strip this out of extension method, so the best way out would be to create differently named wrapper:
fun <T> T.debug (tag: String = "value"): T {
debugWrapper( "$tag: $this")
return this
}
fun debug (message: String) {
Log.d ("tag", message)
}
private fun debugWrapper (message: String) {
debug(message)
}
I think you were looking to keep existing calls to debug and this delivers.
I've tried to look into decompiled code (minus the default parameter, for clarity) in hope to differentiate them by namespace:
public final class TestclassKt {
public static final Object debug(Object $this$debug, #NotNull String tag) {
Intrinsics.checkNotNullParameter(tag, "tag");
debug($this$debug, tag + ": " + $this$debug);
return $this$debug;
}
public static final void debug(#NotNull String message) {
Intrinsics.checkNotNullParameter(message, "message");
Log.d("tag", message);
}
}
But the 2 methods are in same namespace and the only way to differentiate them is by arguments.
I think you've broken Kotlin.

How to parse kafka message in KafkaSpout and set in tuple value

I am trying to read kafka messages from KafkaSpout and set tuple values from json that are parsed from that message. Actually, I am creating an additional Bolt that parses a tuple field called "value" with json string from KafkaSpout. Is it possible to set these values in Spout?
class ScanConfigKafkaSpout(kafkaUrl: String, kafkaGroup: String, kafkaTopic: String) : KafkaSpout<String, String>(
KafkaSpoutConfig
.builder(kafkaUrl, kafkaTopic)
.setProp(KEY_KAFKA_GROUP, "grp1")
.setProcessingGuarantee(KafkaSpoutConfig.ProcessingGuarantee.AT_MOST_ONCE)
.build()
), ComponentId {
override fun open(conf: MutableMap<String, Any>?, context: TopologyContext?, collector: SpoutOutputCollector?) {
try {
logger.debug("<${id()}> Opening ScanConfigKafkaSpout with ${conf.toString()}")
super.open(conf, context, collector)
logger.debug("<${id()}> ScanConfigKafkaSpout opened")
} catch (t: Throwable) {
logger.error("<${id()}> Error during opening CrawlScanConfigKafkaSpout", t)
}
}
override fun id(): String = SCAN_CONFIG_KAFKA_SPOUT
companion object {
private val logger = LoggerFactory.getLogger(ScanConfigKafkaSpout::class.java)
}
}
You probably need to implement the method declareOutputFields(OutputFieldsDeclarer declarer from IComponent.
It is used by Storm to serialize your attribute values and tuple configurations.
As stated here in the section Data Model , it says:
Every node in a topology must declare the output fields for the tuples it emits.
There is also a java example given for that method.
#Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("double", "triple"));
}

Spring webflux error handler: How to get the reactor context of the request in the error handler?

Spring boot 2.1.5 Project Reactor 3.2.9
In my webflux project, I extensively use the reactor contexts in order to pass around some values.
My purpose here is to be able to get the context inside of the Exception handler.
A simple example:
#Component
#Order(-2)
public class GlobalErrorWebExceptionHandler extends
AbstractErrorWebExceptionHandler {
public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ApplicationContext applicationContext, ServerCodecConfigurer configurer) {
super(errorAttributes, resourceProperties, applicationContext);
this.setMessageWriters(configurer.getWriters());
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(
ErrorAttributes errorAttributes) {
return RouterFunctions
.route(RequestPredicates.all(), request -> {
Throwable error = errorAttributes.getError(request);
return ServerResponse.status(500).syncBody(error.getMessage()).doOnEach(serverResponseSignal -> {
//Here the context is empty because i guess i created a new flux
System.out.println("What is in my context ? " + serverResponseSignal.getContext());
System.out.println("What is my exception ? " + error);
});
});
}
}
I am not sure how to achieve that goal in a clean way with reactor. Anyone an idea ?
I found a trick to be able to achieve that. It does not sound clean but it seems to work.
In a filter, I keep the subscribed context into a request attribute:
#Component
public class MdcWebFilter implements WebFilter {
#NotNull
#Override
public Mono<Void> filter(#NotNull ServerWebExchange serverWebExchange,
WebFilterChain webFilterChain) {
Mono<Void> filter = webFilterChain.filter(serverWebExchange);
return filter
.subscriberContext((context) -> {
//This code is executed before the query
Context contextTmp = context.put("whatever", "whichever");
//I save the context in an attribute attribute
serverWebExchange.getAttributes().put("context", contextTmp);
return contextTmp;
});
}
}
Then after that it is possible to get it from the reactive error handler:
#Component
#Order(-2)
public class GlobalErrorWebExceptionHandler extends
AbstractErrorWebExceptionHandler {
public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ApplicationContext applicationContext, ServerCodecConfigurer configurer) {
super(errorAttributes, resourceProperties, applicationContext);
this.setMessageWriters(configurer.getWriters());
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(
ErrorAttributes errorAttributes) {
return RouterFunctions
.route(RequestPredicates.all(), request -> {
Throwable error = errorAttributes.getError(request);
//The context will be visible in the whole error handling flow
return ServerResponse.status(500).syncBody(error.getMessage())
.subscriberContext((Context) request.attribute("context").orElse(Context.empty())));
});
}
}

Moshi LocalDateTime adapter with multiple format

By default, ThreeTenABP.LocalDateTime is converted to
{"date":{"day":10,"month":4,"year":2018},"time":{"hour":3,"minute":34,"nano":115000000,"second":18}}
I can write an adapter to support ISO date string 2018-04-10T03:45:26.009
class LocalDateTimeAdapter {
#ToJson
fun toJson(value: LocalDateTime): String {
return FORMATTER.format(value)
}
#FromJson
fun fromJson(value: String): LocalDateTime {
return FORMATTER.parse(value, LocalDateTime.FROM)
}
companion object {
private val FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME
}
}
How can I write an adapter which can support both format (fromJson)
{"date":{"day":10,"month":4,"year":2018},"time":{"hour":3,"minute":34,"nano":115000000,"second":18}}
2018-04-10T03:45:26.009
Beside identifying which the format is used in fromJson, I am curious how Moshi internally perform toJson/fromJson for LocalDateTime
You’ll need to use JsonReader.peek() to determine the format of the incoming JSON, and then take action accordingly.
First install an adapter that converts LocalDateTime to a string. That adapter should use a qualifier annotation.
#Retention(RetentionPolicy.RUNTIME)
#JsonQualifier
#interface DateString {
}
Next create the string adapter. It should be straightforward, and might delegate to Moshi’s built-in Rfc3339DateJsonAdapter.
public final class LocalDateAsStringAdapter {
#ToJson String toJson(#DateString LocalDateTime localDateTime) {
...
}
#FromJson #DateString LocalDateTime fromJson(String string) {
...
}
}
Finally create an adapter that delegates either to Moshi’s built in adapter (that one will use {...}) or to your string adapter. This one prefers the string format, but you can do what you like.
public final class MultipleFormatsDateAdapter {
#ToJson void toJson(JsonWriter writer, LocalDateTime value,
#DateString JsonAdapter<LocalDateTime> stringAdapter) throws IOException {
stringAdapter.toJson(writer, value);
}
#FromJson LocalDateTime fromJson(JsonReader reader, #DateString JsonAdapter<LocalDateTime> stringAdapter,
JsonAdapter<LocalDateTime> defaultAdapter) throws IOException {
if (reader.peek() == JsonReader.Token.STRING) {
return stringAdapter.fromJson(reader);
} else {
return defaultAdapter.fromJson(reader);
}
}
}
This works because Moshi lets you declare multiple JsonAdapter arguments to the #ToJson and #FromJson methods, and these arguments may be annotated.
It also relies on the way this feature works if the types are the same. Here we’re making a JsonAdapter<LocalDateTime> by delegating to another JsonAdapter<LocalDateTime>. When the types are the same Moshi uses its nextAdapter() feature for composition.

JAX-RS ExceptionMapper throws MessageBodyProviderNotFoundException

Using JAX-RS, I have successfully implemented an ExceptionMapper for Exceptions that do not require a more sophisticated response than an HTTP status code, as follows.
#Provider
public class ISBNNotFoundManager implements ExceptionMapper<ISBNNotFoundException>{
#Override
public Response toResponse(ISBNNotFoundException exception) {
return Response.status(NOT_FOUND).build();
}
}
This works as expected.
However, I want to respond with something more useful when bean validation fails. The follow code snippet results in a MessageBodyProviderNotFoundException.
#Provider
public class ConstraintViolationExceptionMapper implements
ExceptionMapper<ConstraintViolationException> {
#Override
#Produces(MediaType.APPLICATION_JSON)
public Response toResponse(ConstraintViolationException exception) {
final Map<String, String> errorResponse =
exception.getConstraintViolations()
.stream()
.collect(
Collectors.toMap(o -> o.getPropertyPath().toString(), o -> o.getMessage()));
return Response.status(Response.Status.BAD_REQUEST).entity(errorResponse).build();
}
}
When a bean validation occurs the response includes the HTTP response code 500 and the root cause is given as follow:
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException:
MessageBodyWriter not found for media type=application/json,
type=class java.util.HashMap, genericType=class java.util.HashMap.
What I have tried that didn't work:
Wrapping the Map in a GenericEntity like so. The same result as above:
new GenericEntity>(errorResponse) {}
What I tried the DID work:
Wrapping the map in a custom POJO, DataIntegrityValidation, as follows:
#XmlRootElement
public class DataIntegrityValidation {
private Map<String, String> errorResponse = new HashMap<>();
public Map<String, String> getErrorResponse() {
return errorResponse;
}
public void setErrorResponse(Map<String, String> errorResponse) {
this.errorResponse = errorResponse;
}
}
Then in the toResponse method I wrap the map in the DataIntegrityValidation POJO like so and add it to the response object.
DataIntegrityValidation dataIntegrityValidation =
new DataIntegrityValidation();
dataIntegrityValidation.setErrorResponse(errorResponse);
return
Response.status(Response.Status.BAD_REQUEST)
.entity(dataIntegrityValidation).build();
This gives the following JSON:
{
"errorResponse": {
"entry": [
{
"key": "saveBook.arg0.description",
"value": "size must be between 100 and 2147483647"
},
{
"key": "saveBook.arg0.published",
"value": "must be in the past"
},
{
"key": "saveBook.arg0.link",
"value": "must match \"^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$\""
}
]
}
}
I can live with this but would really like to know why it cannot handle the Map even though it is wrapped in the Generic Entity.
All responses welcome.
The reason the marshalling failed for both Map and GenericEntity is because there is no JAXB definition associated with them. And when you wrapped the map in a POJO annotated with #XmlRootElement; it was able to marshal it correctly.