Keycloak doesn't boot with custom action token spi - keycloak

I'm a couple of custom SPIs to Keycloak(6.0.1) and I need also to create a custom action token which will be sent to the user.
I've created a custom event listener, email sender, required action and deploy all these in a single jar.
When I'm trying to put the action token handler with proper manifest entries I get this
Caused by: java.lang.NoClassDefFoundError: Failed to link com/mycompany/providers/registration/actiontoken/Invitati
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1095)
at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:424)
at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:555)
at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:339)
at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:126)
at org.jboss.modules.Module.loadModuleClass(Module.java:731)
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:247)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(ServiceLoader.java:1209)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1220)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1264)
at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1299)
at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1384)
at org.keycloak.keycloak-services#6.0.1//org.keycloak.provider.DefaultProviderLoader.load(DefaultProviderLoader.java:60)
Definition of the handler
package com.mycompany.providers.registration.actiontoken;
import org.keycloak.TokenVerifier;
import
org.keycloak.authentication.actiontoken.AbstractActionTokenHander;
import org.keycloak.authentication.actiontoken.ActionTokenContext;
import org.keycloak.authentication.actiontoken.TokenUtils;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
public class InvitationActionTokenHandler extends AbstractActionTokenHander<InvitationActionToken> {
public InvitationActionTokenHandler(String id, Class<InvitationActionToken> tokenClass, String defaultErrorMessage, EventType defaultEventType, String defaultEventError) {
super(id, tokenClass, defaultErrorMessage, defaultEventType, defaultEventError);
}
#Override
public Response handleToken(InvitationActionToken invitationActionToken, ActionTokenContext<InvitationActionToken> tokenContext) {
AuthenticationSessionModel authSession = tokenContext.getAuthenticationSession();
final UriInfo uriInfo = tokenContext.getUriInfo();
final RealmModel realm = tokenContext.getRealm();
EventBuilder event = tokenContext.getEvent();
final KeycloakSession session = tokenContext.getSession();
String nextAction = AuthenticationManager.nextRequiredAction(session, authSession, tokenContext.getClientConnection(), tokenContext.getRequest(), uriInfo, event);
return AuthenticationManager.redirectToRequiredActions(session, realm, authSession, uriInfo, nextAction);
}
#Override
public TokenVerifier.Predicate<? super InvitationActionToken>[] getVerifiers(ActionTokenContext<InvitationActionToken> tokenContext) {
return TokenUtils.predicates(
);
}
}
And the manifest in the file META-INF/services/org.keycloak.authentication.actiontoken.ActionTokenHandlerFactory
com.mycompany.providers.registration.actiontoken.InvitationActionTokenHandler
I've already added probably all dependencies which there are for Keycloak
apply plugin: 'java'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
compileOnly group: 'org.keycloak', name: 'keycloak-model-jpa', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-services', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-server-spi', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-server-spi-private', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-core', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-common', version: '6.0.1'
EDIT: updates
So I pinpointed that the class ActionTokenHandler is not available in the classpath, verified with this snippet in an SPI which is already working
try {
Class cls = Class.forName("org.keycloak.authentication.actiontoken.ActionTokenHandler");
} catch (ClassNotFoundException e) {
//is thrown always
e.printStackTrace();
}
I've changed my gradle dependencies to compileOnly to make sure no classpath issues would happen

You have to provide list of package dependencies to application server. Create jboss-deployment-structure.xml in src/main/resources/META-INF directory with the following content:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-core" />
<module name="org.keycloak.keycloak-server-spi" />
<module name="org.keycloak.keycloak-server-spi-private" />
<module name="org.keycloak.keycloak-services" />
<module name="org.keycloak.keycloak-common" />
<module name="org.keycloak.keycloak-model-jpa" />
</dependencies>
</deployment>
</jboss-deployment-structure>

Related

JAX-RS not responding at all (404)

I'm using Eclipse 2020-03, Gradle and Tomcat. all I did follows.
Installing gradle through eclipse marketplace.
making gradle project.
adding those on build.gradle dependencies
dependencies {
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:28.2-jre'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.27'
compile group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27'
compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.4.0-b180830.0359'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.27'
}
adding "rest" package on src/main/java
adding ApplicationConfig.java and RestApiService.java on rest package.
ApplicationConfig.java
package rest;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/api")
public class ApplicationConfig extends Application {
#Override
public Map<String, Object> getProperties(){
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("jersey.config.server.provider.packages", "A_UnivG.rest");
return properties;
}
}
RestApiService.java
package rest;
import java.util.logging.Logger;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import Data.*;
#Path("/Data")
public class RestApiService {
Logger logger = Logger.getLogger("RestApiService");
IntegrationDAO dao = new IntegrationDAO();
#GET
#Path("hello")
#Produces(MediaType.TEXT_PLAIN)
public String getHello() {return "Hello";}
}
and when I try to request http://localhost:portnumber/A_UnivG/api/Data/hello it spits out only 404 error.
cannot figure out why.
My project works with plain jsp files. I have a JSP page which uses DAO Read but it works just fine. well, that shouldn't be a problem I just tried hello world and it doesn't work at all.

Spring cloud gateway configuration issue in Kubernetes service discovery

I am trying to use spring cloud gateway with kubernetes service discovery. Below is the setup which i am using
build.gradle
plugins {
id 'org.springframework.boot' version '2.2.0.BUILD-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
ext {
set('springCloudVersion', "Hoxton.BUILD-SNAPSHOT")
set('springCloudKubernetesVersion', "1.0.3.RELEASE")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes'
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-ribbon'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "org.springframework.cloud:spring-cloud-kubernetes-dependencies:${springCloudKubernetesVersion}"
}
}
test {
useJUnitPlatform()
}
application.yml
spring:
application.name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true
kubernetes:
reload:
enabled: true
server:
port: 8080
logging:
level:
org.springframework.cloud.gateway: TRACE
org.springframework.cloud.loadbalancer: TRACE
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
enabled: true
info:
enabled: true
DemoApplication.java
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
#SpringBootApplication
#EnableDiscoveryClient
#RestController
public class DemoApplication {
#Autowired
private DiscoveryClient discoveryClient;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#GetMapping("/services")
public List<String> services() {
return this.discoveryClient.getServices();
}
}
Spring cloud gateway is not able to redirect the request to other services. The log being printed is
2019-10-13 18:29:38.303 TRACE 1 --- [or-http-epoll-2]
o.s.c.g.f.WeightCalculatorWebFilter : Weights attr: {} 2019-10-13
18:29:38.305 TRACE 1 --- [or-http-epoll-2]
o.s.c.g.h.RoutePredicateHandlerMapping : No RouteDefinition found
for [Exchange: GET http://gateway-url/service-name/hello]
Although when I call http://<gateway-url>/services, then I can see the list of all services. So all the permission is being provided at pod level and service discovery is working fine. I am pretty sure there is some configuration, which i am missing but I am not able to figure it out even after looking at documentation several times.
So, it looks like there is an issue in Spring Cloud Hoxton.M3 release, as it's working fine with Hoxton.M2.
I have opened an issue for the same.

Using Jersey with Open Liberty in Gradle

I have a simple setup with gradle and Open Liberty. From this blogpost https://openliberty.io/blog/2018/12/14/microprofile21-18004.html
it says
"Open Liberty now has reactive extensions to JAX-RS 2.1 so that you can use providers from Apache CXF and Jersey"
But I can't get it to work with Jersey
I've tried various configurations of my build.gradle file and server.xml but still can't get it to work and find documentation lacking.
build.gradle
apply plugin: 'war'
apply plugin: 'liberty'
apply plugin: 'java-library'
group = 'x.y.z'
version = '1.0-SNAPSHOT'
description = "X Y Z"
sourceCompatibility = 1.8
targetCompatibility = 1.8
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'net.wasdev.wlp.gradle.plugins:liberty-gradle-plugin:2.6.3'
}
}
repositories {
mavenCentral()
}
//required for compiling, testing and running the application
dependencies {
implementation group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.26'
implementation group: 'org.glassfish.jersey.core', name: 'jersey-common', version: '2.26'
implementation group: 'org.glassfish.jersey.core', name: 'jersey-server', version: '2.26'
providedCompile group:'javax.servlet', name:'javax.servlet-api', version:'3.1.0'
testCompile group:'commons-httpclient', name:'commons-httpclient', version:'3.1'
testCompile group:'junit', name:'junit', version:'4.12'
libertyRuntime group:'io.openliberty', name:'openliberty-runtime', version:'19.0.0.3'
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:27.0.1-jre'
testImplementation 'junit:junit:4.12'
}
//Extra properties for project level
ext {
appName = project.name
testServerHttpPort = 9080
testServerHttpsPort = 9443
warContext = appName
}
liberty {
server {
name = "${appName}Server"
configFile = file("src/main/liberty/config/server.xml")
bootstrapProperties = ['default.http.port': testServerHttpPort,
'default.https.port': testServerHttpsPort,
'app.context.root': warContext]
packageLiberty {
archive = "$buildDir/${appName}.zip"
include = "usr"
}
}
}
war {
archiveName = "${baseName}.${extension}"
}
//unit test configuration
test {
reports.html.destination = file("$buildDir/reports/unit")
reports.junitXml.destination = file("$buildDir/test-results/unit")
exclude '**/it/**'
}
//integration test configuration
task integrationTest(type: Test) {
group 'Verification'
description 'Runs the integration tests.'
reports.html.destination = file("$buildDir/reports/it")
reports.junitXml.destination = file("$buildDir/test-results/it")
include '**/it/**'
exclude '**/unit/**'
systemProperties = ['liberty.test.port': testServerHttpPort, 'war.name': warContext]
}
task openBrowser {
description = 'Open browser to http://localhost:8080/${warContext}'
doLast {
java.awt.Desktop.desktop.browse
"http://localhost:${testServerHttpPort}/${appName}".toURI()
}
}
task openTestReport {
description = 'Open browser to the test report'
doLast {
java.awt.Desktop.desktop.browse file("$buildDir/reports/it/index.html").toURI()
}
}
clean.dependsOn 'libertyStop'
check.dependsOn 'integrationTest'
integrationTest.dependsOn 'libertyStart'
integrationTest.finalizedBy 'libertyStop'
integrationTest.finalizedBy 'openTestReport'
libertyPackage.dependsOn 'libertyStop'
server.xml
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">
<featureManager>
<!-- <feature>jsp-2.3</feature> -->
<!-- <feature>jaxrs-2.1</feature> -->
<feature>servlet-4.0</feature>
<!--
-->
</featureManager>
<httpEndpoint id="defaultHttpEndpoint"
httpPort="${default.http.port}"
httpsPort="${default.https.port}" />
<applicationManager autoExpand="true"/>
<webApplication contextRoot="${app.context.root}" location="${app.context.root}.war" />
</server>
HelloWorldService
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
#Path("/hello")
public class HelloWorldService {
#GET
#Path("/{param}")
public Response getMsg(#PathParam("param") String msg) {
String output = "Jersey say : " + msg;
return Response.status(200).entity(output).build();
}
}
When I try to hit the endpoint I get a 404
curl localhost:9080/XYZ/hello/jersey
Error 404: java.io.FileNotFoundException: SRVE0190E: File not found: /hello/jersey
Any help MUCH appreciated!

Using Spring Cloud Stream to produce Avro Messages using the Confluent Schema Registry

I am new to Spring Cloud Stream and trying to produce Avro messages based on the Confluent Schema Registry.
I can get the very basic example, https://cloud.spring.io/spring-cloud-stream/ working, but when I try to extend it further to use Avro, I am getting exceptions.
As a generic test environment, I am running the Docker image:
https://github.com/Landoop/fast-data-dev/
The test project was generated and slightly modified using Spring Initializr:
https://start.spring.io/
The pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo.kafka</groupId>
<artifactId>kafka-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>kafka-demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR1</spring-cloud.version>
<project-avro.version>7.0.0-SNAPSHOT</project-avro.version>
<apache.avro.version>1.8.2</apache.avro.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-schema</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
<version>${apache.avro.version}</version>
</dependency>
<dependency>
<groupId>project.foundation</groupId>
<artifactId>maritz-avro</artifactId>
<version>${project-avro.version}</version>
</dependency>
</dependencies>
</project>
I have published the following schema to the registry:
{
"type": "record",
"name": "RoutingSlipMsg",
"fields": [
{
"name": "projectNumber",
"type": "string"
},
{
"name": "clientName",
"type": "string"
},
{
"name": "programTheme",
"type": "string"
},
{
"name": "databaseName",
"type": [
"null",
"string"
]
},
{
"name": "actionType",
"type": [
"null",
"string"
]
}
]
}
Original Test application.yml
spring:
cloud:
stream:
schema:
avro:
dynamicSchemaGenerationEnabled: true
bindings:
output:
binder: kafka
destination: routing_slip_dev
# contentType: application/avro
# contentType: application/*+avro
contentType: application/com.project.RoutingSlipMsg.v1+avro
schemaRegistryClient:
endpoint: http://192.168.99.100:8081
kafka:
binder:
defaultBrokerPort: 9092
defaultZkPort: 2181
zkNodes: 192.168.99.100
brokers: 192.168.99.100
Test application.yml edits:
spring:
cloud:
stream:
schema:
avro:
dynamicSchemaGenerationEnabled: true
bindings:
output:
binder: kafka
destination: routing_slip_dev
# contentType: application/*+avro
# contentType: application/avro
schemaRegistryClient:
endpoint: http://192.168.99.100:8081
kafka:
binder:
defaultBrokerPort: 9092
defaultZkPort: 2181
zkNodes: 192.168.99.100
brokers: 192.168.99.100
Configuration class
#Configuration
public class DemoConfiguration {
#Bean
public ConfluentSchemaRegistryClient schemaRegistryClient() {
ConfluentSchemaRegistryClient registry = new ConfluentSchemaRegistryClient();
registry.setEndpoint("http://192.168.99.100:8081");
return registry;
}
}
The auto topic creation seems to be working properly. I can change the destination: value to something else each time and a new topic will be created.
Test
package com.project.kafka.kafkademo;
import com.project.avro.RoutingSlipMsg;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class KafkaDemoApplicationTests {
#Autowired
private KafkaRoutingSlipSender kafkaRoutingSlipSender;
#Test
public void testSend() throws Exception {
RoutingSlipMsg routingSlip = new RoutingSlipMsg();
routingSlip.setActionType("FAKE_ACTION");
routingSlip.setClientName("TEST_CLIENT");
routingSlip.setDatabaseName("NONE");
routingSlip.setProgramTheme("THEME");
routingSlip.setProjectNumber("ABC123");
kafkaRoutingSlipSender.send(routingSlip);
}
}
**BootApplication class*
package com.project.kafka.kafkademo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class KafkaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(KafkaDemoApplication.class, args);
}
}
Original Sender class
package com.project.kafka.kafkademo;
import com.project.avro.RoutingSlipMsg;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.cloud.stream.schema.client.EnableSchemaRegistryClient;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.core.MessageSource;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Component;
#Component
#EnableBinding(Source.class)
#EnableSchemaRegistryClient
public class KafkaRoutingSlipSender {
#InboundChannelAdapter(value = Source.OUTPUT)
public MessageSource<RoutingSlipMsg> send(RoutingSlipMsg data) {
System.out.println("**** Hello World ****");
return () -> {
return new GenericMessage<>(data);
};
}
}
Sender Class Edits:
#Component
#EnableBinding(Source.class)
#EnableSchemaRegistryClient
public class KafkaRoutingSlipSender {
#Autowired
private Source source;
public void send(RoutingSlipMsg data) {
System.out.println("**** Hello World ****");
source.output().send(MessageBuilder.withPayload(data).build());
}
}
Original Stacktrace / Exception due to inappropriate use of #InboundChannelAdapter
2017-07-06 12:20:48.645 ERROR 69011 --- [ask-scheduler-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessagingException: Failed to invoke method; nested exception is java.lang.IllegalArgumentException: wrong number of arguments
at org.springframework.integration.endpoint.MethodInvokingMessageSource.doReceive(MethodInvokingMessageSource.java:119)
at org.springframework.integration.endpoint.AbstractMessageSource.receive(AbstractMessageSource.java:134)
at org.springframework.integration.endpoint.SourcePollingChannelAdapter.receiveMessage(SourcePollingChannelAdapter.java:224)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:245)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.access$000(AbstractPollingEndpoint.java:58)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:190)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:186)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller$1.run(AbstractPollingEndpoint.java:353)
at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:55)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:51)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:344)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:216)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:201)
at org.springframework.integration.endpoint.MethodInvokingMessageSource.doReceive(MethodInvokingMessageSource.java:116)
... 20 more
I have reviewed several different posts on here, but nothing seems to be helping.
What might I be missing?
Update 1:
I have made updates to the KafkaRoutingSlipSender class and the application.yml as shown above. With the contentType removed, these changes will publish a message like:
ÿcontentType?"application/x-java-object;type=com.maritz.avro.RoutingSlipMsg"FAKE_ACTIOÎTEST_CLIENÔNONÅTHEMÅABC12³
to the topic.
However, when I set the contentType to application/*+avro, the #Autowired Source appears to be casuing a NullPointerException.
New Stacktrace / Exception:
org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'output'; nested exception is java.lang.NullPointerException
, failedMessage=GenericMessage [payload={"projectNumber": "ABC123", "clientName": "TEST_CLIENT", "programTheme": "THEME", "databaseName": "NONE", "actionType": "FAKE_ACTION"}, headers={id=9a9ebc45-9431-8de5-1cb0-40d191082599, timestamp=1499438830456}]
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:449)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
at com.maritz.kafka.kafkademo.KafkaRoutingSlipSender.send(KafkaRoutingSlipSender.java:22)
at com.maritz.kafka.kafkademo.KafkaDemoApplicationTests.testSend(KafkaDemoApplicationTests.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.NullPointerException
at org.springframework.cloud.stream.schema.client.DefaultSchemaRegistryClient.register(DefaultSchemaRegistryClient.java:57)
at org.springframework.cloud.stream.schema.avro.AvroSchemaRegistryClientMessageConverter.resolveSchemaForWriting(AvroSchemaRegistryClientMessageConverter.java:242)
at org.springframework.cloud.stream.schema.avro.AbstractAvroMessageConverter.convertToInternal(AbstractAvroMessageConverter.java:174)
at org.springframework.messaging.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:193)
at org.springframework.cloud.stream.binding.MessageConverterConfigurer$ContentTypeConvertingInterceptor.preSend(MessageConverterConfigurer.java:253)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
... 31 more
Update 2 (07-10-2017):
I have fixed the null Source issue, thanks to this information:
Spring Boot: Configuration Class is simply ignored and not loaded
The ConfluentSchemaRegistryClient is now being used. I can step into the code when debugging, but it doesn't find the schema.
ConfluentSchemaRegistryClient.register(String subject, String format, String schema)
ResponseEntity<Map> response = this.template.exchange(this.endpoint + path, HttpMethod.POST, request, Map.class, new Object[0]);
New Stacktrace / Exception (07-10-2017):
org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'output'; nested exception is org.springframework.web.client.HttpClientErrorException: 404 Not Found
, failedMessage=GenericMessage [payload={"projectNumber": "ABC123", "clientName": "TEST_CLIENT", "programTheme": "THEME", "databaseName": "NONE", "actionType": "FAKE_ACTION"}, headers={id=73365130-a91b-ba9c-aaf0-77cfaa26f73d, timestamp=1499700409997}]
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:449)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
at com.maritz.kafka.kafkademo.KafkaRoutingSlipSender.send(KafkaRoutingSlipSender.java:29)
at com.maritz.kafka.kafkademo.KafkaDemoApplicationTests.testSend(KafkaDemoApplicationTests.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.springframework.web.client.HttpClientErrorException: 404 Not Found
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
at org.springframework.cloud.stream.schema.client.ConfluentSchemaRegistryClient.register(ConfluentSchemaRegistryClient.java:73)
at org.springframework.cloud.stream.schema.avro.AvroSchemaRegistryClientMessageConverter.resolveSchemaForWriting(AvroSchemaRegistryClientMessageConverter.java:242)
at org.springframework.cloud.stream.schema.avro.AbstractAvroMessageConverter.convertToInternal(AbstractAvroMessageConverter.java:174)
at org.springframework.messaging.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:193)
at org.springframework.cloud.stream.binding.MessageConverterConfigurer$ContentTypeConvertingInterceptor.preSend(MessageConverterConfigurer.java:253)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
... 31 more
Is the register() supposed to be creating a new schema if that one doesn't exist, or is the 404 appropriate behavior? Quite confused.
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
An #InboundChannelAdapter method cannot have any parameters...
/**
* Indicates that a method is capable of producing a {#link org.springframework.messaging.Message}
* or {#link org.springframework.messaging.Message} {#code payload}.
* <p>
* A method annotated with {#code #InboundChannelAdapter} can't accept any parameters.
* <p>
* Return values from the annotated method may be of any type. If the return
* value is not a {#link org.springframework.messaging.Message}, a {#link org.springframework.messaging.Message}
* will be created with that object as its {#code payload}.
...
It is polled for a message, or message payload.
So what you see as application/x-java-object;type=com.maritz.avro.RoutingSlipMsg is because the default contentType for java objects is to serialize using Kryo, and that's what it set as contentType.
Since you want to use Confluent Schema Registry, that is not the default one, you need to setup a ConfluentSchemaRegistryClient bean, check it here how to enable it: http://docs.spring.io/spring-cloud-stream/docs/Ditmars.BUILD-SNAPSHOT/reference/htmlsingle/#_schema_registry_client
You now have a DefaultSchemaRegistryClient and it's probably having issues since the REST interface between the default server and confluent are not the same.
We are working on the docs, should be ready soon. In the meantime just expose this on your application:
#Bean
public SchemaRegistryClient schemaRegistryClient(#Value("${spring.cloud.stream.schemaRegistryClient.endpoint}") String endpoint){
ConfluentSchemaRegistryClient client = new ConfluentSchemaRegistryClient();
client.setEndpoint(endpoint);
return client;
}

Gradle GWT multiproject, compileGwt not finding subproject classpath

I have a multiproject GWt Gradle where the compileGwt from gradle does not find a subproject but if I use the standard Eclipse GWT plugin it compiles fine
When building through gradle I get the following error
:main:compileGwt
Loading inherited module 'com.stratebo.gwt.client.main.MainPage'
Loading inherited module 'com.stratebo.gwt.common'
[ERROR] Unable to find 'com/stratebo/gwt/common.gwt.xml' on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source?
the project structure is as follows:
TMSRoot
|--settings.gradle
|--build.gradle
|--CommonGwt
|----build.gradle
|--main
|----build.gradle
The Tms Root settings.gradle
include "CommonGWT", "main"
The TmsRoot build.gradle
subprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.8.2'
}
version = '1.0'
jar {
manifest.attributes provider: 'Stratebo Technologies'
}
}
project('main'){
dependencies {
compile project(":CommonGWT")
}
}
The CommonGWT build.gradle
apply plugin: 'war'
apply plugin: 'java'
apply plugin: 'gwt'
apply plugin: 'eclipse'
apply plugin: 'jetty'
dependencies {
compile 'org.slf4j:slf4j-api:1.7.12'
testCompile 'junit:junit:4.12'
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
version = '1.0'
buildscript {
repositories {
jcenter() //repository where to fetch gwt gradle plugin
}
dependencies {
classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6'
classpath files(project(":CommonGWT").sourceSets.main.java.srcDirs)
}
}
repositories {
mavenCentral()
}
compileJava{
options.incremental = true
}
gwt {
gwtVersion='2.7.0'
modules 'com.stratebo.gwt.common'
sourceSets {
main {
java {
srcDir 'src'
}
}
}
logLevel = 'ERROR'
minHeapSize = "512M";
maxHeapSize = "1024M";
superDev {
noPrecompile=true
}
Eclipse.
eclipse{
addGwtContainer=false // Default set to true
}
jettyRunWar.httpPort = 8089
}
task wrapper(type: Wrapper) {
gradleVersion = '2.8'
}
The main build.gradle
apply plugin: 'war'
apply plugin: 'java'
apply plugin: 'gwt'
apply plugin: 'eclipse'
apply plugin: 'jetty'
dependencies {
compile 'org.slf4j:slf4j-api:1.7.12'
testCompile 'junit:junit:4.12'
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
version = '1.0'
dependencies{
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
compile group: 'commons-codec', name: 'commons-codec', version: '1.5'
compile group: 'org.gwtbootstrap3', name: 'gwtbootstrap3', version: '0.9.1'
compile group: 'junit', name: 'junit', version: '4.11'
compile project(':CommonGWT')
testCompile group: 'junit', name: 'junit', version: '4.+'
}
def platformSources() {
return files('../CommonGWT/src/main/java', '../CommonGWT/src/main/resources')
}
buildscript {
repositories {
jcenter() //repository where to fetch gwt gradle plugin
}
dependencies {
classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6'
}
}
repositories {
mavenCentral()
}
compileJava{
options.incremental = true
}
gwt {
gwtVersion='2.7.0'
modules 'com.stratebo.gwt.client.main.MainPage'
sourceSets {
main {
java {
srcDir 'src'
}
}
}
logLevel = 'ERROR'
minHeapSize = "512M";
maxHeapSize = "1024M";
superDev {
noPrecompile=true
}
eclipse{
addGwtContainer=false // Default set to true
}
//Specify the deployment Port
jettyRunWar.httpPort = 8089
}
task wrapper(type: Wrapper) {
gradleVersion = '2.8'
}
the CommonGWt common.gwt.xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.6.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.6.1/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name="com.google.gwt.user.User" />
<inherits name="com.stratebo.gwt.common" />
<source path="client" />
<source path="common" />
</module>
And finally the Main MainPage.gwt.xml
<module>
<inherits name="org.gwtbootstrap3.GwtBootstrap3NoTheme" />
<inherits name="com.google.gwt.user.User" />
<stylesheet src="/mytheme.cache.css" />
<entry-point class="com.stratebo.gwt.client.main.MainPage">
</entry-point>
<inherits name="com.stratebo.gwt.common" />
<source path="client" />
<source path="common" />
</module>
any help greatly appreciated
I think that you you are missing the sources from your commonGWT project that you could add to your jar commonGWT build.gradle :
jar {
from sourceSets.main.allSource
}
The commonGWT jar will contain the sources that will allow the compilation of the dependent project.