Repository: provectus/kafka-ui
Issue: Listing topic's fails : /ui/clusters/environment1/topics 
Labels: type/bug
scope/backend

**Describe the bug**
(A clear and concise description of what the bug is.)
Listing topic's fails : /ui/clusters/environment1/topics 
07:40:04.776 [main] WARN  org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JodaDateTimeJacksonConfiguration - Auto-configuration of Jackson's Joda-Time integration is deprecated in favor of using java.time (JSR-310).
07:40:05.311 [main] WARN  org.springframework.http.converter.json.Jackson2ObjectMapperBuilder - For Jackson Kotlin classes support please add "com.fasterxml.jackson.module:jackson-module-kotlin" to the classpath
07:40:05.818 [main] INFO  com.provectus.kafka.ui.serde.DeserializationService - Using SchemaRegistryAwareRecordSerDe for cluster 'environment1'
07:40:05.884 [main] WARN  org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'deserializationService': Invocation of init method failed; nested exception is java.lang.RuntimeException: Can't init deserializer
07:40:05.979 [main] INFO  org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener -

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
07:40:05.981 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'deserializationService': Invocation of init method failed; nested exception is java.lang.RuntimeException: Can't init deserializer
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-2.2.4.RELEASE.jar!/:2.2.4.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.4.RELEASE.jar!/:2.2.4.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.4.RELEASE.jar!/:2.2.4.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.4.RELEASE.jar!/:2.2.4.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.4.RELEASE.jar!/:2.2.4.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.4.RELEASE.jar!/:2.2.4.RELEASE]
        at com.provectus.kafka.ui.KafkaUiApplication.main(KafkaUiApplication.java:14) [classes!/:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [kafka-ui-api.jar:?]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [kafka-ui-api.jar:?]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:51) [kafka-ui-api.jar:?]
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52) [kafka-ui-api.jar:?]
Caused by: java.lang.RuntimeException: Can't init deserializer
        at com.provectus.kafka.ui.serde.DeserializationService.createRecordDeserializerForCluster(DeserializationService.java:44) ~[classes!/:?]
        at java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:178) ~[?:?]
        at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) ~[?:?]
        at java.util.concurrent.ConcurrentHashMap$ValueSpliterator.forEachRemaining(ConcurrentHashMap.java:3605) ~[?:?]
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[?:?]
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[?:?]
        at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[?:?]
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
        at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[?:?]
        at com.provectus.kafka.ui.serde.DeserializationService.init(DeserializationService.java:27) ~[classes!/:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        ... 26 more
Caused by: java.lang.NullPointerException
        at java.util.Objects.requireNonNull(Objects.java:222) ~[?:?]
        at com.provectus.kafka.ui.serde.schemaregistry.SchemaRegistryAwareRecordSerDe.createSchemaRegistryClient(SchemaRegistryAwareRecordSerDe.java:72) ~[classes!/:?]
        at com.provectus.kafka.ui.serde.schemaregistry.SchemaRegistryAwareRecordSerDe.<init>(SchemaRegistryAwareRecordSerDe.java:101) ~[classes!/:?]
        at com.provectus.kafka.ui.serde.DeserializationService.createRecordDeserializerForCluster(DeserializationService.java:41) ~[classes!/:?]
        at java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:178) ~[?:?]
        at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) ~[?:?]
        at java.util.concurrent.ConcurrentHashMap$ValueSpliterator.forEachRemaining(ConcurrentHashMap.java:3605) ~[?:?]
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[?:?]
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[?:?]
        at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[?:?]
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
        at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[?:?]
        at com.provectus.kafka.ui.serde.DeserializationService.init(DeserializationService.java:27) ~[classes!/:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
        ... 26 more


**Set up**
(How do you run the app?)
today's image from master in docker store
docker pull provectuslabs/kafka-ui:master

**Steps to Reproduce**
Steps to reproduce the behavior:

1. goto topic section for given environment

**Expected behavior**
(A clear and concise description of what you expected to happen)

**Screenshots**
(If applicable, add screenshots to help explain your problem)


**Additional context**
(Add any other context about the problem here)

Issue comments:
 Hi, @sreenivasvp. Thanks for creating issue. We'll try to fix it in current release.
Hello, @sreenivasvp! Could you please share your docker-compose file?

@MarselAhmetov 

      containers:
        - image: provectuslabs/kafka-ui:master
          imagePullPolicy: Always
          name: kafka-ui
          resources:
            limits:
              cpu: 1000m
              memory: 2Gi
            requests:
              cpu: 1000m
              memory: 2Gi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          ports:
            - containerPort: 8080
              name: server
            - containerPort: 5012
              name: jmx
      - env:
        - name: KAFKA_CLUSTERS_0_NAME
          value: ENV1
        - name: KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS
          value: headless.ENV1-kafka:9094
        - name: KAFKA_CLUSTERS_0_ZOOKEEPER
          value: headless.ENV1-kafka:2181
        - name: KAFKA_CLUSTERS_1_NAME
          value: ENV2
        - name: KAFKA_CLUSTERS_1_BOOTSTRAPSERVERS
          value: headless.ENV2-kafka:9094
        - name: KAFKA_CLUSTERS_1_ZOOKEEPER
          value: headless.ENV2-kafka:2181
        - name: KAFKA_CLUSTERS_2_NAME
          value: ENV3
        - name: KAFKA_CLUSTERS_2_BOOTSTRAPSERVERS
          value: headless.ENV3-kafka:9094
        - name: KAFKA_CLUSTERS_2_ZOOKEEPER
          value: headless.ENV3-kafka:2181


Pull request review comments:
as far as I see there should not be situation when getSchemaRegistry() != null but getSchemaRegistry().getUrl() == null ? If so, getUrl() != null check is redundant
same here

Patch that resolved the issue:
diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/mapper/ClusterMapper.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/mapper/ClusterMapper.java
index 380fe7d8534..9d2e3fc09a8 100644
--- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/mapper/ClusterMapper.java
+++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/mapper/ClusterMapper.java
@@ -35,6 +35,7 @@
 import java.nio.file.Path;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.stream.Collectors;
 import org.apache.kafka.clients.admin.ConfigEntry;
@@ -91,7 +92,8 @@ default ConfigSynonym toConfigSynonym(ConfigEntry.ConfigSynonym config) {
   Partition toPartition(InternalPartition topic);
 
   default InternalSchemaRegistry setSchemaRegistry(ClustersProperties.Cluster clusterProperties) {
-    if (clusterProperties == null) {
+    if (clusterProperties == null
+        || clusterProperties.getSchemaRegistry() == null) {
       return null;
     }
 
diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/serde/schemaregistry/SchemaRegistryAwareRecordSerDe.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/serde/schemaregistry/SchemaRegistryAwareRecordSerDe.java
index 03f1431b82d..747f5c61afa 100644
--- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/serde/schemaregistry/SchemaRegistryAwareRecordSerDe.java
+++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/serde/schemaregistry/SchemaRegistryAwareRecordSerDe.java
@@ -68,8 +68,9 @@ public class SchemaRegistryAwareRecordSerDe implements RecordSerDe {
   private final ObjectMapper objectMapper = new ObjectMapper();
 
   private static SchemaRegistryClient createSchemaRegistryClient(KafkaCluster cluster) {
-    Objects.requireNonNull(cluster.getSchemaRegistry());
-    Objects.requireNonNull(cluster.getSchemaRegistry().getUrl());
+    if (cluster.getSchemaRegistry() == null) {
+      throw new ValidationException("schemaRegistry is not specified");
+    }
     List<SchemaProvider> schemaProviders =
         List.of(new AvroSchemaProvider(), new ProtobufSchemaProvider(), new JsonSchemaProvider());
 


Test patch: