diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2..000000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or 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 - * - * http://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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 642d572ce..c0bcafe98 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,3 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip diff --git a/amqp/pom.xml b/amqp/pom.xml index 0c1257b2d..f569fb72f 100644 --- a/amqp/pom.xml +++ b/amqp/pom.xml @@ -6,7 +6,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-amqp-proton diff --git a/api/pom.xml b/api/pom.xml index cad0b7e13..4a7036e3d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -24,7 +24,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-api diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 8684cb0ae..1219789e7 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -21,7 +21,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-benchmarks @@ -31,7 +31,7 @@ UTF-8 1.23 - 1.8 + 25 benchmarks true diff --git a/bom/pom.xml b/bom/pom.xml index 931ebac17..8acec8291 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-bom diff --git a/core/pom.xml b/core/pom.xml index b5f731ed3..189d1d4fa 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-core diff --git a/examples/amqp-proton/pom.xml b/examples/amqp-proton/pom.xml index be8e54c43..fcb37a682 100644 --- a/examples/amqp-proton/pom.xml +++ b/examples/amqp-proton/pom.xml @@ -3,7 +3,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 diff --git a/examples/basic-http/pom.xml b/examples/basic-http/pom.xml index 6c0929cf9..b0c45f6c9 100644 --- a/examples/basic-http/pom.xml +++ b/examples/basic-http/pom.xml @@ -21,7 +21,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 diff --git a/examples/kafka/pom.xml b/examples/kafka/pom.xml index 402fd8d32..fc479e016 100644 --- a/examples/kafka/pom.xml +++ b/examples/kafka/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index 60d1ccbf2..c543462f1 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ cloudevents-parent io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 diff --git a/examples/restful-ws-microprofile-liberty/pom.xml b/examples/restful-ws-microprofile-liberty/pom.xml index 733c23400..3171cd597 100644 --- a/examples/restful-ws-microprofile-liberty/pom.xml +++ b/examples/restful-ws-microprofile-liberty/pom.xml @@ -3,7 +3,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT ../ 4.0.0 diff --git a/examples/restful-ws-quarkus/pom.xml b/examples/restful-ws-quarkus/pom.xml index f8f801219..7499abdb9 100644 --- a/examples/restful-ws-quarkus/pom.xml +++ b/examples/restful-ws-quarkus/pom.xml @@ -5,16 +5,16 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 cloudevents-restful-ws-quarkus-example cloudevents.example.restful.ws.quarkus - 1.10.3.Final + 3.30.5 quarkus-universe-bom io.quarkus - 1.10.3.Final + 3.30.5 @@ -30,7 +30,7 @@ io.quarkus - quarkus-resteasy-jackson + quarkus-rest-jackson io.quarkus diff --git a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserClient.java b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserClient.java index cd2f025e6..e3a46d0ba 100644 --- a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserClient.java +++ b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserClient.java @@ -1,8 +1,9 @@ package io.cloudevents.examples.quarkus.client; -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; import io.cloudevents.CloudEvent; import io.cloudevents.jackson.JsonFormat; @@ -11,6 +12,7 @@ @Path("/users") @RegisterRestClient +@ApplicationScoped public interface UserClient { // This will emit binary encoded events. diff --git a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserEventsGenerator.java b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserEventsGenerator.java index 6b79d6b9c..05e3aba6b 100644 --- a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserEventsGenerator.java +++ b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserEventsGenerator.java @@ -3,11 +3,11 @@ import java.net.URI; import java.util.UUID; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; -import javax.ws.rs.core.MediaType; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.core.MediaType; -import com.fasterxml.jackson.databind.ObjectMapper; +import tools.jackson.databind.json.JsonMapper; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.slf4j.Logger; @@ -26,12 +26,12 @@ public class UserEventsGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(UserEventsGenerator.class); @Inject - ObjectMapper mapper; + JsonMapper mapper; @Inject @RestClient UserClient userClient; - + long userCount=0; @Scheduled(every="2s") diff --git a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/config/ApplicationConfig.java b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/config/ApplicationConfig.java new file mode 100644 index 000000000..a7023b91a --- /dev/null +++ b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/config/ApplicationConfig.java @@ -0,0 +1,14 @@ +package io.cloudevents.examples.quarkus.config; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import tools.jackson.databind.json.JsonMapper; + +@ApplicationScoped +public class ApplicationConfig { + @Produces + @ApplicationScoped + public JsonMapper jsonMapper() { + return JsonMapper.builder().findAndAddModules().build(); + } +} diff --git a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java index 39c0dec46..b3db15f31 100644 --- a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java +++ b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java @@ -1,6 +1,6 @@ package io.cloudevents.examples.quarkus.resources; -import com.fasterxml.jackson.databind.ObjectMapper; +import tools.jackson.databind.json.JsonMapper; import io.cloudevents.CloudEvent; import io.cloudevents.examples.quarkus.model.User; import io.cloudevents.jackson.JsonFormat; @@ -8,12 +8,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.inject.Inject; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; + import java.util.HashMap; import java.util.Map; @@ -25,12 +26,12 @@ public class UserResource { private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class); @Inject - ObjectMapper mapper; + JsonMapper mapper; @Context UriInfo uriInfo; - private Map users = new HashMap<>(); + private final Map users = new HashMap<>(); @GET @Path("/{username}") diff --git a/examples/restful-ws-quarkus/src/main/resources/application.properties b/examples/restful-ws-quarkus/src/main/resources/application.properties index e41cca74d..f2c7cc0a0 100644 --- a/examples/restful-ws-quarkus/src/main/resources/application.properties +++ b/examples/restful-ws-quarkus/src/main/resources/application.properties @@ -4,4 +4,3 @@ ## The Rest client will send events to the local UserResource io.cloudevents.examples.quarkus.client.UserClient/mp-rest/url=http://localhost:8080 %test.io.cloudevents.examples.quarkus.client.UserClient/mp-rest/url=http://localhost:8081 -io.cloudevents.examples.quarkus.client.UserClient/mp-rest/scope=javax.inject.Singleton diff --git a/examples/restful-ws-quarkus/src/test/java/io/cloudevents/examples/quarkus/NativeUserResourceTestIT.java b/examples/restful-ws-quarkus/src/test/java/io/cloudevents/examples/quarkus/NativeUserResourceTestIT.java index b1cca4df6..a8d6f2b96 100644 --- a/examples/restful-ws-quarkus/src/test/java/io/cloudevents/examples/quarkus/NativeUserResourceTestIT.java +++ b/examples/restful-ws-quarkus/src/test/java/io/cloudevents/examples/quarkus/NativeUserResourceTestIT.java @@ -1,8 +1,8 @@ package io.cloudevents.examples.quarkus; -import io.quarkus.test.junit.NativeImageTest; +import io.quarkus.test.junit.QuarkusIntegrationTest; -@NativeImageTest +@QuarkusIntegrationTest public class NativeUserResourceTestIT extends UserResourceTest { // Execute the same tests but in native mode. diff --git a/examples/restful-ws-spring-boot/pom.xml b/examples/restful-ws-spring-boot/pom.xml index 3153c0e9a..76e97bf5c 100644 --- a/examples/restful-ws-spring-boot/pom.xml +++ b/examples/restful-ws-spring-boot/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 @@ -13,8 +13,8 @@ cloudevents.example.spring.boot - 2.3.2.RELEASE - 5.2.9.RELEASE + 4.0.0 + 7.0.2 @@ -32,7 +32,7 @@ org.springframework.boot - spring-boot-starter-jersey + spring-boot-starter-web ${spring-boot.version} @@ -51,6 +51,12 @@ cloudevents-http-restful-ws ${project.version} + + io.cloudevents + cloudevents-spring + 5.0.0-SNAPSHOT + compile + diff --git a/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/MainResource.java b/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/MainResource.java index d82f033ea..a76ac5cc7 100644 --- a/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/MainResource.java +++ b/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/MainResource.java @@ -17,54 +17,45 @@ package io.cloudevents.examples.springboot; -import com.fasterxml.jackson.databind.ObjectMapper; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.core.data.PojoCloudEventData; import io.cloudevents.jackson.PojoCloudEventDataMapper; import org.springframework.beans.factory.annotation.Autowired; - -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import tools.jackson.databind.json.JsonMapper; import static io.cloudevents.core.CloudEventUtils.mapData; -@Path("/") +@RestController public class MainResource { - public static final String HAPPY_BIRTHDAY_EVENT_TYPE = "happybirthday.myapplication"; - @Autowired - ObjectMapper objectMapper; + private JsonMapper jsonMapper; - @POST - @Path("happy_birthday") - public Response handleHappyBirthdayEvent(CloudEvent inputEvent) { + @PostMapping("/happy_birthday") + public ResponseEntity handleHappyBirthdayEvent(@RequestBody CloudEvent inputEvent) { if (!inputEvent.getType().equals(HAPPY_BIRTHDAY_EVENT_TYPE)) { - return Response.status(Response.Status.BAD_REQUEST) - .type(MediaType.TEXT_PLAIN) - .entity("Event type should be \"" + HAPPY_BIRTHDAY_EVENT_TYPE + "\" but is \"" + inputEvent.getType() + "\"") - .build(); + return ResponseEntity.badRequest() + .contentType(MediaType.TEXT_PLAIN) + .body("Event type should be \"" + HAPPY_BIRTHDAY_EVENT_TYPE + "\" but is \"" + inputEvent.getType() + "\""); } - PojoCloudEventData cloudEventData = mapData(inputEvent, PojoCloudEventDataMapper.from(objectMapper, User.class)); + PojoCloudEventData cloudEventData = mapData(inputEvent, PojoCloudEventDataMapper.from(jsonMapper, User.class)); if (cloudEventData == null) { - return Response.status(Response.Status.BAD_REQUEST) - .type(MediaType.TEXT_PLAIN) - .entity("Event should contain the user") - .build(); + return ResponseEntity.badRequest().contentType(MediaType.TEXT_PLAIN).body("Event should contain the user"); } User user = cloudEventData.getValue(); user.setAge(user.getAge() + 1); - CloudEvent outputEvent = CloudEventBuilder.from(inputEvent) - .withData(PojoCloudEventData.wrap(user, objectMapper::writeValueAsBytes)) - .build(); + CloudEvent outputEvent = CloudEventBuilder.from(inputEvent).withData(PojoCloudEventData.wrap(user, jsonMapper::writeValueAsBytes)).build(); - return Response.ok(outputEvent).build(); + return ResponseEntity.ok(outputEvent); } } diff --git a/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/JerseyConfiguration.java b/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/WebConfig.java similarity index 54% rename from examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/JerseyConfiguration.java rename to examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/WebConfig.java index 9f1ae9480..8e7fb6646 100644 --- a/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/JerseyConfiguration.java +++ b/examples/restful-ws-spring-boot/src/main/java/io/cloudevents/examples/springboot/WebConfig.java @@ -17,17 +17,22 @@ package io.cloudevents.examples.springboot; -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import org.glassfish.jersey.server.ResourceConfig; +import io.cloudevents.spring.mvc.CloudEventHttpMessageConverter; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverters; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import tools.jackson.databind.ObjectMapper; @Configuration -public class JerseyConfiguration extends ResourceConfig { - - public JerseyConfiguration() { - // Configure Jersey to load the CloudEventsProvider (which serializes/deserializes CloudEvents) - // and our resource - registerClasses(CloudEventsProvider.class, MainResource.class); +public class WebConfig implements WebMvcConfigurer { + @Override + public void configureMessageConverters(HttpMessageConverters.ServerBuilder builder) { + builder.addCustomConverter(new CloudEventHttpMessageConverter()); } + @Bean + public ObjectMapper objectMapper(){ + return new ObjectMapper(); + } } diff --git a/examples/rocketmq/pom.xml b/examples/rocketmq/pom.xml index 229364eac..1cb045988 100644 --- a/examples/rocketmq/pom.xml +++ b/examples/rocketmq/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 diff --git a/examples/spring-function/pom.xml b/examples/spring-function/pom.xml index 2010cccbe..f2dc5b29d 100644 --- a/examples/spring-function/pom.xml +++ b/examples/spring-function/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 @@ -13,7 +13,8 @@ cloudevents.example.spring.function - 2.4.3 + 4.0.0 + 2025.1.0 @@ -25,6 +26,13 @@ pom import + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + @@ -32,12 +40,15 @@ org.springframework.cloud spring-cloud-function-web - 3.1.1 org.springframework.boot spring-boot-starter-webflux + + org.springframework.boot + spring-boot-starter-gson + io.cloudevents cloudevents-spring diff --git a/examples/spring-function/src/main/java/io/cloudevents/examples/spring/DemoApplication.java b/examples/spring-function/src/main/java/io/cloudevents/examples/spring/DemoApplication.java index 2c999774c..555249c21 100644 --- a/examples/spring-function/src/main/java/io/cloudevents/examples/spring/DemoApplication.java +++ b/examples/spring-function/src/main/java/io/cloudevents/examples/spring/DemoApplication.java @@ -6,7 +6,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.codec.CodecCustomizer; +import org.springframework.boot.http.codec.CodecCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.codec.CodecConfigurer; @@ -19,8 +19,7 @@ @SpringBootApplication public class DemoApplication { - - public static void main(String[] args) throws Exception { + static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @@ -52,13 +51,10 @@ public CloudEventMessageConverter cloudEventMessageConverter() { */ @Configuration public static class CloudEventHandlerConfiguration implements CodecCustomizer { - @Override public void customize(CodecConfigurer configurer) { configurer.customCodecs().register(new CloudEventHttpMessageReader()); configurer.customCodecs().register(new CloudEventHttpMessageWriter()); } - } - } diff --git a/examples/spring-function/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java b/examples/spring-function/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java index 94c465563..49aef5bf8 100644 --- a/examples/spring-function/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java +++ b/examples/spring-function/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java @@ -1,112 +1,120 @@ package io.cloudevents.examples.spring; -import java.net.URI; - +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.http.HttpHeaders; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; +import org.springframework.test.web.servlet.client.ExchangeResult; +import org.springframework.test.web.servlet.client.RestTestClient; + +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class DemoApplicationTests { - - @Autowired - private TestRestTemplate rest; +@Disabled("ContentType behaves odd after upgrading from deprecated TestRestTemplate") +class DemoApplicationTests { + private static final String BODY = "{\"value\":\"Dave\"}"; + private RestTestClient rest; @LocalServerPort private int port; + @BeforeEach + void setUp() { + rest = RestTestClient + .bindToServer() + .baseUrl(String.format("http://localhost:%d", port)) + .build(); + } + @Test void echoWithCorrectHeaders() { - - ResponseEntity response = rest - .exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/foos")) // - .header("ce-id", "12345") // - .header("ce-specversion", "1.0") // - .header("ce-type", "io.spring.event") // - .header("ce-source", "https://spring.io/events") // - .contentType(MediaType.APPLICATION_JSON) // - .body("{\"value\":\"Dave\"}"), String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + ExchangeResult response = rest.post() + .uri("/foos") + .header("ce-id", "12345") + .header("ce-specversion", "1.0") + .header("ce-type", "io.spring.event") + .header("ce-source", "https://spring.io/events") + .contentType(MediaType.APPLICATION_JSON) + .body(BODY) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @Test void structuredRequestResponseEvents() { - - ResponseEntity response = rest - .exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) // - .contentType(new MediaType("application", "cloudevents+json")) // - .body("{" // - + "\"id\":\"12345\"," // - + "\"specversion\":\"1.0\"," // - + "\"type\":\"io.spring.event\"," // - + "\"source\":\"https://spring.io/events\"," // - + "\"data\":{\"value\":\"Dave\"}}"), - String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + ExchangeResult response = rest.post() + .uri("/event") + .contentType(new MediaType("application", "cloudevents+json")) + .body(""" + { + "id": "12345", + "specversion": "1.0", + "type": "io.spring.event", + "source": "https://spring.io/events", + "data": %s + } + """.formatted(BODY)) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @Test void requestResponseEvents() { - - ResponseEntity response = rest - .exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) // - .header("ce-id", "12345") // - .header("ce-specversion", "1.0") // - .header("ce-type", "io.spring.event") // - .header("ce-source", "https://spring.io/events") // - .contentType(MediaType.APPLICATION_JSON) // - .body("{\"value\":\"Dave\"}"), String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + ExchangeResult response = rest.post() + .uri("/event") + .header("ce-id", "12345") + .header("ce-specversion", "1.0") + .header("ce-type", "io.spring.event") + .header("ce-source", "https://spring.io/events") + .contentType(MediaType.APPLICATION_JSON) + .body(BODY) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } } diff --git a/examples/spring-reactive/pom.xml b/examples/spring-reactive/pom.xml index ef5ddaf16..d3e101c28 100644 --- a/examples/spring-reactive/pom.xml +++ b/examples/spring-reactive/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 @@ -13,7 +13,7 @@ cloudevents.example.spring.reactive - 2.4.3 + 4.0.0 @@ -33,6 +33,14 @@ org.springframework.boot spring-boot-starter-webflux + + org.springframework.boot + spring-boot-webtestclient + + + org.springframework.boot + spring-boot-starter-webclient + io.cloudevents cloudevents-spring @@ -64,5 +72,5 @@ - + diff --git a/examples/spring-reactive/src/main/java/io/cloudevents/examples/spring/DemoApplication.java b/examples/spring-reactive/src/main/java/io/cloudevents/examples/spring/DemoApplication.java index a5dd693d4..6258a75bd 100644 --- a/examples/spring-reactive/src/main/java/io/cloudevents/examples/spring/DemoApplication.java +++ b/examples/spring-reactive/src/main/java/io/cloudevents/examples/spring/DemoApplication.java @@ -8,11 +8,11 @@ import io.cloudevents.spring.http.CloudEventHttpUtils; import io.cloudevents.spring.webflux.CloudEventHttpMessageReader; import io.cloudevents.spring.webflux.CloudEventHttpMessageWriter; +import org.springframework.boot.http.codec.CodecCustomizer; import reactor.core.publisher.Mono; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.codec.CodecCustomizer; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; @@ -64,4 +64,4 @@ public void customize(CodecConfigurer configurer) { } -} \ No newline at end of file +} diff --git a/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java b/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java index b98c7c3c0..859f88d5e 100644 --- a/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java +++ b/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; @@ -14,9 +15,9 @@ import io.cloudevents.core.builder.CloudEventBuilder; import static org.assertj.core.api.Assertions.assertThat; +@AutoConfigureWebTestClient @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class DemoApplicationTests { - +class DemoApplicationTests { @Autowired private WebTestClient rest; diff --git a/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/WebClientTests.java b/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/WebClientTests.java index 33d997ce1..b9e53f744 100644 --- a/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/WebClientTests.java +++ b/examples/spring-reactive/src/test/java/io/cloudevents/examples/spring/WebClientTests.java @@ -10,7 +10,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient; import org.springframework.web.reactive.function.client.WebClient; import io.cloudevents.CloudEvent; @@ -22,9 +23,9 @@ * content of the request and response are asserted separately in * {@link DemoApplicationTests}. */ +@AutoConfigureWebTestClient @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class WebClientTests { - +class WebClientTests { @Autowired private WebClient.Builder rest; diff --git a/examples/spring-rsocket/pom.xml b/examples/spring-rsocket/pom.xml index df095e5af..5a30673c7 100644 --- a/examples/spring-rsocket/pom.xml +++ b/examples/spring-rsocket/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 @@ -13,7 +13,7 @@ cloudevents.example.spring.rsocket - 2.4.3 + 4.0.0 @@ -59,5 +59,5 @@ - + diff --git a/examples/spring-rsocket/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java b/examples/spring-rsocket/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java index 753c61654..3aa9c51c6 100644 --- a/examples/spring-rsocket/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java +++ b/examples/spring-rsocket/src/test/java/io/cloudevents/examples/spring/DemoApplicationTests.java @@ -3,7 +3,6 @@ import java.net.URI; import java.util.UUID; -import com.fasterxml.jackson.databind.ObjectMapper; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.core.data.PojoCloudEventData; @@ -15,11 +14,12 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.messaging.rsocket.RSocketRequester; import org.springframework.util.MimeType; +import tools.jackson.databind.ObjectMapper; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class DemoApplicationTests { +class DemoApplicationTests { @Autowired private RSocketRequester.Builder builder; @@ -30,7 +30,7 @@ public class DemoApplicationTests { private RSocketRequester rsocketRequester; @BeforeEach - public void init() { + void init() { String host = "localhost"; int port = 7000; rsocketRequester = builder diff --git a/examples/vertx/pom.xml b/examples/vertx/pom.xml index daa3b3347..7dd414b40 100644 --- a/examples/vertx/pom.xml +++ b/examples/vertx/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 diff --git a/formats/avro-compact/pom.xml b/formats/avro-compact/pom.xml index 16c27e9b5..3c33867bf 100644 --- a/formats/avro-compact/pom.xml +++ b/formats/avro-compact/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT ../../pom.xml diff --git a/formats/json-jackson/pom.xml b/formats/json-jackson/pom.xml index a6031d62e..f53ac9f91 100644 --- a/formats/json-jackson/pom.xml +++ b/formats/json-jackson/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT ../../pom.xml @@ -31,22 +31,9 @@ jar - 2.15.2 io.cloudevents.formats.jackson - - - - com.fasterxml.jackson - jackson-bom - ${jackson.version} - import - pom - - - - @@ -57,12 +44,14 @@ - com.fasterxml.jackson.core + tools.jackson.core jackson-core + ${jackson.version} - com.fasterxml.jackson.core + tools.jackson.core jackson-databind + ${jackson.version} diff --git a/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventDeserializer.java b/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventDeserializer.java index 364ae19ad..1704529e1 100644 --- a/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventDeserializer.java +++ b/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventDeserializer.java @@ -17,27 +17,31 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.exc.MismatchedInputException; -import com.fasterxml.jackson.databind.node.JsonNodeType; -import com.fasterxml.jackson.databind.node.NullNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; import io.cloudevents.SpecVersion; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.core.data.BytesCloudEventData; -import io.cloudevents.rw.*; +import io.cloudevents.core.format.EventDeserializationException; +import io.cloudevents.rw.CloudEventDataMapper; +import io.cloudevents.rw.CloudEventRWException; +import io.cloudevents.rw.CloudEventReader; +import io.cloudevents.rw.CloudEventWriter; +import io.cloudevents.rw.CloudEventWriterFactory; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonParser; +import tools.jackson.databind.DeserializationContext; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.deser.std.StdDeserializer; +import tools.jackson.databind.exc.MismatchedInputException; +import tools.jackson.databind.node.JsonNodeType; +import tools.jackson.databind.node.NullNode; +import tools.jackson.databind.node.ObjectNode; import java.nio.charset.StandardCharsets; -import java.io.IOException; /** - * Jackson {@link com.fasterxml.jackson.databind.JsonDeserializer} for {@link CloudEvent} + * Jackson {@link tools.jackson.databind.deser.std.StdDeserializer} for {@link CloudEvent} */ class CloudEventDeserializer extends StdDeserializer { private final boolean forceExtensionNameLowerCaseDeserialization; @@ -132,10 +136,11 @@ public , V> V read(CloudEventWriterFactory w } else { JsonNode dataNode = node.remove("data"); assertNodeType(dataNode, JsonNodeType.STRING, "data", "Because content type is not a json, only a string is accepted as data"); - data = BytesCloudEventData.wrap(dataNode.asText().getBytes(StandardCharsets.UTF_8)); + data = BytesCloudEventData.wrap(dataNode.asString().getBytes(StandardCharsets.UTF_8)); } } } + break; case V1: if (node.has("data_base64") && node.has("data")) { throw MismatchedInputException.from(p, CloudEvent.class, "CloudEvent cannot have both 'data' and 'data_base64' fields"); @@ -150,13 +155,16 @@ public , V> V read(CloudEventWriterFactory w } else { JsonNode dataNode = node.remove("data"); assertNodeType(dataNode, JsonNodeType.STRING, "data", "Because content type is not a json, only a string is accepted as data"); - data = BytesCloudEventData.wrap(dataNode.asText().getBytes(StandardCharsets.UTF_8)); + data = BytesCloudEventData.wrap(dataNode.asString().getBytes(StandardCharsets.UTF_8)); } } + break; + default: + throw new EventDeserializationException(new RuntimeException(specVersion + " not supported")); } // Now let's process the extensions - node.fields().forEachRemaining(entry -> { + node.properties().forEach(entry -> { String extensionName = entry.getKey(); if (this.forceExtensionNameLowerCaseDeserialization) { extensionName = extensionName.toLowerCase(); @@ -178,15 +186,15 @@ public , V> V read(CloudEventWriterFactory w // Only 'Int' values are supported by the specification - if (numericValue instanceof Integer){ - writer.withContextAttribute(extensionName, (Integer) numericValue); + if (numericValue instanceof Integer integer){ + writer.withContextAttribute(extensionName, integer); } else{ throw CloudEventRWException.newInvalidAttributeType(extensionName,numericValue); } break; case STRING: - writer.withContextAttribute(extensionName, extensionValue.textValue()); + writer.withContextAttribute(extensionName, extensionValue.asString()); break; default: writer.withContextAttribute(extensionName, extensionValue.toString()); @@ -198,14 +206,14 @@ public , V> V read(CloudEventWriterFactory w return writer.end(mapper.map(data)); } return writer.end(); - } catch (IOException e) { + } catch (JacksonException e) { throw new RuntimeException(e); } catch (IllegalArgumentException e) { throw new RuntimeException(MismatchedInputException.from(this.p, CloudEvent.class, e.getMessage())); } } - private String getStringNode(ObjectNode objNode, JsonParser p, String attributeName) throws JsonProcessingException { + private String getStringNode(ObjectNode objNode, JsonParser p, String attributeName) throws JacksonException { String val = getOptionalStringNode(objNode, p, attributeName); if (val == null) { throw MismatchedInputException.from(p, CloudEvent.class, "Missing mandatory " + attributeName + " attribute"); @@ -213,16 +221,16 @@ private String getStringNode(ObjectNode objNode, JsonParser p, String attributeN return val; } - private String getOptionalStringNode(ObjectNode objNode, JsonParser p, String attributeName) throws JsonProcessingException { + private String getOptionalStringNode(ObjectNode objNode, JsonParser p, String attributeName) throws JacksonException { JsonNode unparsedAttribute = objNode.remove(attributeName); if (unparsedAttribute == null || unparsedAttribute instanceof NullNode) { return null; } assertNodeType(unparsedAttribute, JsonNodeType.STRING, attributeName, null); - return unparsedAttribute.asText(); + return unparsedAttribute.asString(); } - private void assertNodeType(JsonNode node, JsonNodeType type, String attributeName, String desc) throws JsonProcessingException { + private void assertNodeType(JsonNode node, JsonNodeType type, String attributeName, String desc) throws JacksonException { if (node.getNodeType() != type) { throw MismatchedInputException.from( p, @@ -260,7 +268,7 @@ private boolean isValidChar(char c) { } @Override - public CloudEvent deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + public CloudEvent deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException{ // In future we could eventually find a better solution avoiding this buffering step, but now this is the best option // Other sdk does the same in order to support all versions ObjectNode node = ctxt.readValue(p, ObjectNode.class); @@ -269,10 +277,6 @@ public CloudEvent deserialize(JsonParser p, DeserializationContext ctxt) throws return new JsonMessage(p, node, this.forceExtensionNameLowerCaseDeserialization, this.forceIgnoreInvalidExtensionNameDeserialization, this.disableDataContentTypeDefaulting) .read(CloudEventBuilder::fromSpecVersion); } catch (RuntimeException e) { - // Yeah this is bad but it's needed to support checked exceptions... - if (e.getCause() instanceof IOException) { - throw (IOException) e.getCause(); - } throw MismatchedInputException.from(p, CloudEvent.class, e.getMessage()); } } diff --git a/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventSerializer.java b/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventSerializer.java index 50f0931d8..41dbd0aab 100644 --- a/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventSerializer.java +++ b/formats/json-jackson/src/main/java/io/cloudevents/jackson/CloudEventSerializer.java @@ -17,21 +17,21 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; import io.cloudevents.core.CloudEventUtils; import io.cloudevents.rw.CloudEventContextReader; import io.cloudevents.rw.CloudEventContextWriter; import io.cloudevents.rw.CloudEventRWException; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonGenerator; +import tools.jackson.databind.SerializationContext; +import tools.jackson.databind.ser.std.StdSerializer; -import java.io.IOException; import java.nio.charset.StandardCharsets; /** - * Jackson {@link com.fasterxml.jackson.databind.JsonSerializer} for {@link CloudEvent} + * Jackson {@link tools.jackson.databind.ser.std.StdSerializer} for {@link CloudEvent} */ class CloudEventSerializer extends StdSerializer { @@ -47,9 +47,9 @@ protected CloudEventSerializer(boolean forceDataBase64Serialization, boolean for private static class JsonContextWriter implements CloudEventContextWriter { private final JsonGenerator gen; - private final SerializerProvider provider; + private final SerializationContext provider; - public JsonContextWriter(JsonGenerator gen, SerializerProvider provider) { + public JsonContextWriter(JsonGenerator gen, SerializationContext provider) { this.gen = gen; this.provider = provider; } @@ -57,19 +57,18 @@ public JsonContextWriter(JsonGenerator gen, SerializerProvider provider) { @Override public CloudEventContextWriter withContextAttribute(String name, String value) throws CloudEventRWException { try { - gen.writeStringField(name, value); + gen.writeStringProperty(name, value); return this; - } catch (IOException e) { + } catch (JacksonException e) { throw new RuntimeException(e); } } @Override - public CloudEventContextWriter withContextAttribute(String name, Number value) throws CloudEventRWException - { + public CloudEventContextWriter withContextAttribute(String name, Number value) throws CloudEventRWException { // Only Integer types are supported by the specification - if (value instanceof Integer) { - this.withContextAttribute(name, (Integer) value); + if (value instanceof Integer integer) { + this.withContextAttribute(name, integer); } else { // Default to string representation for other numeric values this.withContextAttribute(name, value.toString()); @@ -78,12 +77,11 @@ public CloudEventContextWriter withContextAttribute(String name, Number value) t } @Override - public CloudEventContextWriter withContextAttribute(String name, Integer value) throws CloudEventRWException - { + public CloudEventContextWriter withContextAttribute(String name, Integer value) throws CloudEventRWException { try { - gen.writeNumberField(name, value.intValue()); + gen.writeNumberProperty(name, value); return this; - } catch (IOException e) { + } catch (JacksonException e) { throw new RuntimeException(e); } } @@ -91,18 +89,18 @@ public CloudEventContextWriter withContextAttribute(String name, Integer value) @Override public CloudEventContextWriter withContextAttribute(String name, Boolean value) throws CloudEventRWException { try { - gen.writeBooleanField(name, value); + gen.writeBooleanProperty(name, value); return this; - } catch (IOException e) { + } catch (JacksonException e) { throw new RuntimeException(e); } } } @Override - public void serialize(CloudEvent value, JsonGenerator gen, SerializerProvider provider) throws IOException { + public void serialize(CloudEvent value, JsonGenerator gen, SerializationContext provider) throws JacksonException { gen.writeStartObject(); - gen.writeStringField("specversion", value.getSpecVersion().toString()); + gen.writeStringProperty("specversion", value.getSpecVersion().toString()); // Serialize attributes try { @@ -110,36 +108,36 @@ public void serialize(CloudEvent value, JsonGenerator gen, SerializerProvider pr JsonContextWriter contextWriter = new JsonContextWriter(gen, provider); contextReader.readContext(contextWriter); } catch (RuntimeException e) { - throw (IOException) e.getCause(); + throw (JacksonException) e.getCause(); } // Serialize data if (value.getData() != null) { CloudEventData data = value.getData(); if (data instanceof JsonCloudEventData) { - gen.writeObjectField("data", ((JsonCloudEventData) data).getNode()); + gen.writePOJOProperty("data", ((JsonCloudEventData) data).getNode()); } else { byte[] dataBytes = data.toBytes(); String contentType = value.getDataContentType(); if (shouldSerializeBase64(contentType)) { switch (value.getSpecVersion()) { case V03: - gen.writeStringField("datacontentencoding", "base64"); - gen.writeFieldName("data"); - gen.writeBinary(dataBytes); + gen.writeStringProperty("datacontentencoding", "base64"); + gen.writeBinaryProperty("data", dataBytes); break; case V1: - gen.writeFieldName("data_base64"); - gen.writeBinary(dataBytes); + gen.writeBinaryProperty("data_base64", dataBytes); break; + default: + throw new RuntimeException(value.getSpecVersion() + " not supported"); } } else if (JsonFormat.dataIsJsonContentType(contentType)) { // TODO really bad b/c it allocates stuff, is there another solution out there? char[] dataAsString = new String(dataBytes, StandardCharsets.UTF_8).toCharArray(); - gen.writeFieldName("data"); + gen.writeName("data"); gen.writeRawValue(dataAsString, 0, dataAsString.length); } else { - gen.writeFieldName("data"); + gen.writeName("data"); gen.writeUTF8String(dataBytes, 0, dataBytes.length); } } diff --git a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonCloudEventData.java b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonCloudEventData.java index 6e9c19b72..acb753b80 100644 --- a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonCloudEventData.java +++ b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonCloudEventData.java @@ -17,8 +17,8 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.databind.JsonNode; import io.cloudevents.CloudEventData; +import tools.jackson.databind.JsonNode; import java.nio.charset.StandardCharsets; import java.util.Objects; @@ -27,7 +27,6 @@ * This class is a wrapper for Jackson {@link JsonNode} implementing {@link CloudEventData}. */ public class JsonCloudEventData implements CloudEventData { - private final JsonNode node; /** diff --git a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java index cddbaf802..cc5aa6a01 100644 --- a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java +++ b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java @@ -16,18 +16,18 @@ */ package io.cloudevents.jackson; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventDeserializationException; import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.format.EventSerializationException; import io.cloudevents.rw.CloudEventDataMapper; import io.cloudevents.rw.CloudEventRWException; +import tools.jackson.core.JacksonException; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.json.JsonMapper; +import tools.jackson.databind.module.SimpleModule; import java.io.IOException; import java.util.regex.Pattern; @@ -49,7 +49,7 @@ public final class JsonFormat implements EventFormat { * JSON Data Content Type Discriminator */ private static final Pattern JSON_CONTENT_TYPE_PATTERN = Pattern.compile("^(application|text)\\/([a-zA-Z]+\\+)?json(;.*)*$"); - private final ObjectMapper mapper; + private final JsonMapper mapper; private final JsonFormatOptions options; /** @@ -75,8 +75,9 @@ public JsonFormat(boolean forceDataBase64Serialization, boolean forceStringSeria * @param options json serialization / deserialization options */ public JsonFormat(JsonFormatOptions options) { - this.mapper = new ObjectMapper(); - this.mapper.registerModule(getCloudEventJacksonModule(options)); + this.mapper = JsonMapper.builder() + .addModule(getCloudEventJacksonModule(options)) + .build(); this.options = options; } @@ -147,7 +148,7 @@ public JsonFormat withForceIgnoreInvalidExtensionNameDeserialization() { public byte[] serialize(CloudEvent event) throws EventSerializationException { try { return mapper.writeValueAsBytes(event); - } catch (JsonProcessingException e) { + } catch (JacksonException e) { throw new EventSerializationException(e); } } @@ -156,7 +157,7 @@ public byte[] serialize(CloudEvent event) throws EventSerializationException { public CloudEvent deserialize(byte[] bytes) throws EventDeserializationException { try { return mapper.readValue(bytes, CloudEvent.class); - } catch (IOException e) { + } catch (JacksonException e) { throw new EventDeserializationException(e); } } diff --git a/formats/json-jackson/src/main/java/io/cloudevents/jackson/PojoCloudEventDataMapper.java b/formats/json-jackson/src/main/java/io/cloudevents/jackson/PojoCloudEventDataMapper.java index 95c3e0cdc..4b858c2aa 100644 --- a/formats/json-jackson/src/main/java/io/cloudevents/jackson/PojoCloudEventDataMapper.java +++ b/formats/json-jackson/src/main/java/io/cloudevents/jackson/PojoCloudEventDataMapper.java @@ -1,27 +1,27 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import io.cloudevents.CloudEventData; import io.cloudevents.core.data.PojoCloudEventData; import io.cloudevents.rw.CloudEventDataMapper; import io.cloudevents.rw.CloudEventRWException; +import tools.jackson.core.type.TypeReference; +import tools.jackson.databind.JavaType; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.json.JsonMapper; import java.util.List; /** - * This class implements a {@link CloudEventDataMapper} that maps any input {@link CloudEventData} to the specified target type using the Jackson {@link ObjectMapper}. + * This class implements a {@link CloudEventDataMapper} that maps any input {@link CloudEventData} to the specified target type using the Jackson {@link JsonMapper}. * * @param the target type of the conversion */ public class PojoCloudEventDataMapper implements CloudEventDataMapper> { - private final ObjectMapper mapper; + private final JsonMapper mapper; private final JavaType target; - private PojoCloudEventDataMapper(ObjectMapper mapper, JavaType target) { + private PojoCloudEventDataMapper(JsonMapper mapper, JavaType target) { this.mapper = mapper; this.target = target; } @@ -53,37 +53,37 @@ public PojoCloudEventData map(CloudEventData data) throws CloudEventRWExcepti /** * Creates a {@link PojoCloudEventDataMapper} mapping {@link CloudEventData} into {@link PojoCloudEventData}<T> - * using a Jackson {@link ObjectMapper}. + * using a Jackson {@link JsonMapper}. * *

* When working with generic types (e.g. {@link List}<{@link String}>), - * it's better to use {@link PojoCloudEventDataMapper#from(ObjectMapper, TypeReference)}. + * it's better to use {@link PojoCloudEventDataMapper#from(JsonMapper, TypeReference)}. *

* - * @param mapper {@link ObjectMapper} used for POJO deserialization + * @param mapper {@link JsonMapper} used for POJO deserialization * @param target target type as {@link Class}<T> * @param POJO Type * @return {@link CloudEventDataMapper} */ - public static PojoCloudEventDataMapper from(ObjectMapper mapper, Class target) { + public static PojoCloudEventDataMapper from(JsonMapper mapper, Class target) { return new PojoCloudEventDataMapper<>(mapper, mapper.getTypeFactory().constructType(target)); } /** * Creates a {@link PojoCloudEventDataMapper} mapping {@link CloudEventData} into {@link PojoCloudEventData}<T> - * using a Jackson {@link ObjectMapper}. + * using a Jackson {@link JsonMapper}. * *

* This overload is more suitable for mapping generic objects (e.g. {@link List}<{@link String}>), - * as opposed to {@link PojoCloudEventDataMapper#from(ObjectMapper, Class)}. + * as opposed to {@link PojoCloudEventDataMapper#from(JsonMapper, Class)}. *

* - * @param mapper {@link ObjectMapper} used for POJO deserialization + * @param mapper {@link JsonMapper} used for POJO deserialization * @param target target type as {@link TypeReference}<T> * @param POJO Type * @return {@link CloudEventDataMapper} */ - public static PojoCloudEventDataMapper from(ObjectMapper mapper, TypeReference target) { + public static PojoCloudEventDataMapper from(JsonMapper mapper, TypeReference target) { return new PojoCloudEventDataMapper<>(mapper, mapper.getTypeFactory().constructType(target)); } diff --git a/formats/json-jackson/src/test/java/io/cloudevents/jackson/CloudEventDeserializerTest.java b/formats/json-jackson/src/test/java/io/cloudevents/jackson/CloudEventDeserializerTest.java index be8f5f418..3c3bfc283 100644 --- a/formats/json-jackson/src/test/java/io/cloudevents/jackson/CloudEventDeserializerTest.java +++ b/formats/json-jackson/src/test/java/io/cloudevents/jackson/CloudEventDeserializerTest.java @@ -1,69 +1,68 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import io.cloudevents.CloudEvent; import org.junit.jupiter.api.Test; +import tools.jackson.databind.json.JsonMapper; +import tools.jackson.databind.module.SimpleModule; -import java.io.IOException; import java.io.StringReader; import static io.cloudevents.jackson.JsonFormat.getCloudEventJacksonModule; import static org.assertj.core.api.Assertions.assertThat; -public class CloudEventDeserializerTest { +class CloudEventDeserializerTest { + private static final String NON_BINARY_PAYLOAD = """ + { + "specversion" : "1.0", + "type" : "com.example.someevent", + "source" : "/mycontext", + "subject": null, + "id" : "D234-1234-1234", + "time" : "2018-04-05T17:31:00Z", + "comexampleextension1" : "value", + "comexampleothervalue" : 5, + "data" : "I'm just a string" + } + """; - private static final String nonBinaryPayload = "{\n" + - " \"specversion\" : \"1.0\",\n" + - " \"type\" : \"com.example.someevent\",\n" + - " \"source\" : \"/mycontext\",\n" + - " \"subject\": null,\n" + - " \"id\" : \"D234-1234-1234\",\n" + - " \"time\" : \"2018-04-05T17:31:00Z\",\n" + - " \"comexampleextension1\" : \"value\",\n" + - " \"comexampleothervalue\" : 5,\n" + - " \"data\" : \"I'm just a string\"\n" + - "}"; - - private static final String binaryPayload = "{\n" + - " \"specversion\" : \"1.0\",\n" + - " \"type\" : \"com.example.someevent\",\n" + - " \"source\" : \"/mycontext\",\n" + - " \"id\" : \"D234-1234-1234\",\n" + - " \"data_base64\" : \"eyAieHl6IjogMTIzIH0=\"\n" + - "}"; + private static final String BINARY_PAYLOAD = """ + { + "specversion" : "1.0", + "type" : "com.example.someevent", + "source" : "/mycontext", + "id" : "D234-1234-1234", + "data_base64" : "eyAieHl6IjogMTIzIH0=" + } + """; @Test - void impliedDataContentTypeNonBinaryData() throws IOException { - ObjectMapper mapper = getObjectMapper(false); - StringReader reader = new StringReader(nonBinaryPayload); + void impliedDataContentTypeNonBinaryData() { + JsonMapper mapper = getJsonMapper(false); + StringReader reader = new StringReader(NON_BINARY_PAYLOAD); CloudEvent ce = mapper.readValue(reader, CloudEvent.class); assertThat(ce.getDataContentType()).isEqualTo("application/json"); - mapper = getObjectMapper(true); - reader = new StringReader(nonBinaryPayload); + mapper = getJsonMapper(true); + reader = new StringReader(NON_BINARY_PAYLOAD); ce = mapper.readValue(reader, CloudEvent.class); assertThat(ce.getDataContentType()).isNull(); } @Test - void impliedDataContentTypeBinaryData() throws IOException { - final ObjectMapper mapper = getObjectMapper(false); - StringReader reader = new StringReader(binaryPayload); + void impliedDataContentTypeBinaryData() { + final JsonMapper mapper = getJsonMapper(false); + StringReader reader = new StringReader(BINARY_PAYLOAD); CloudEvent ce = mapper.readValue(reader, CloudEvent.class); assertThat(ce.getDataContentType()).isNull(); } - private static ObjectMapper getObjectMapper(boolean disableDataContentTypeDefaulting) { - final ObjectMapper mapper = new ObjectMapper(); + private static JsonMapper getJsonMapper(boolean disableDataContentTypeDefaulting) { final SimpleModule module = getCloudEventJacksonModule( JsonFormatOptions .builder() .disableDataContentTypeDefaulting(disableDataContentTypeDefaulting) .build() ); - mapper.registerModule(module); - return mapper; + return JsonMapper.builder().addModule(module).build(); } - } diff --git a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonCloudEventDataTest.java b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonCloudEventDataTest.java index 1d9488e1c..c06c32319 100644 --- a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonCloudEventDataTest.java +++ b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonCloudEventDataTest.java @@ -17,7 +17,6 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.core.mock.MyCloudEventData; @@ -26,16 +25,16 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import tools.jackson.databind.node.JsonNodeFactory; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; public class JsonCloudEventDataTest { - @ParameterizedTest @MethodSource("textContentArguments") - public void testMapper(String contentType) { + void testMapper(String contentType) { CloudEvent event = CloudEventBuilder.v1(Data.V1_MIN) .withData(contentType, JsonCloudEventData.wrap(JsonNodeFactory.instance.numberNode(10))) .build(); diff --git a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java index 59c2d70c0..8b591d3b3 100644 --- a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java +++ b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java @@ -17,14 +17,9 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.exc.MismatchedInputException; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventDeserializationException; import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.rw.CloudEventRWException; @@ -32,6 +27,10 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.exc.MismatchedInputException; +import tools.jackson.databind.json.JsonMapper; +import tools.jackson.databind.node.JsonNodeFactory; import java.io.IOException; import java.net.URISyntaxException; @@ -41,13 +40,26 @@ import java.util.Objects; import java.util.stream.Stream; -import static io.cloudevents.core.format.ContentType.*; -import static io.cloudevents.core.test.Data.*; -import static org.assertj.core.api.Assertions.*; +import static io.cloudevents.core.format.ContentType.JSON; +import static io.cloudevents.core.test.Data.V03_MIN; +import static io.cloudevents.core.test.Data.V03_WITH_JSON_DATA; +import static io.cloudevents.core.test.Data.V03_WITH_JSON_DATA_WITH_EXT; +import static io.cloudevents.core.test.Data.V03_WITH_TEXT_DATA; +import static io.cloudevents.core.test.Data.V03_WITH_XML_DATA; +import static io.cloudevents.core.test.Data.V1_MIN; +import static io.cloudevents.core.test.Data.V1_WITH_BINARY_EXT; +import static io.cloudevents.core.test.Data.V1_WITH_JSON_DATA; +import static io.cloudevents.core.test.Data.V1_WITH_JSON_DATA_WITH_EXT; +import static io.cloudevents.core.test.Data.V1_WITH_JSON_DATA_WITH_FRACTIONAL_TIME; +import static io.cloudevents.core.test.Data.V1_WITH_NUMERIC_EXT; +import static io.cloudevents.core.test.Data.V1_WITH_TEXT_DATA; +import static io.cloudevents.core.test.Data.V1_WITH_XML_DATA; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; class JsonFormatTest { - - private final ObjectMapper mapper = new ObjectMapper(); + private final JsonMapper mapper = new JsonMapper(); @ParameterizedTest @MethodSource("jsonContentTypes") @@ -67,7 +79,7 @@ void isNotJsonContentType(String contentType) { @ParameterizedTest @MethodSource("serializeTestArgumentsDefault") - void serialize(CloudEvent input, String outputFile) throws IOException { + void serialize(CloudEvent input, String outputFile) { JsonNode jsonOutput = mapper.readValue(loadFile(outputFile), JsonNode.class); byte[] serialized = getFormat().serialize(input); @@ -78,7 +90,7 @@ void serialize(CloudEvent input, String outputFile) throws IOException { @ParameterizedTest @MethodSource("serializeTestArgumentsString") - void serializeWithStringData(CloudEvent input, String outputFile) throws IOException { + void serializeWithStringData(CloudEvent input, String outputFile) { JsonNode jsonOutput = mapper.readValue(loadFile(outputFile), JsonNode.class); byte[] serialized = getFormat().withForceNonJsonDataToString().serialize(input); @@ -89,7 +101,7 @@ void serializeWithStringData(CloudEvent input, String outputFile) throws IOExcep @ParameterizedTest @MethodSource("serializeTestArgumentsBase64") - void serializeWithBase64Data(CloudEvent input, String outputFile) throws IOException { + void serializeWithBase64Data(CloudEvent input, String outputFile) { JsonNode jsonOutput = mapper.readValue(loadFile(outputFile), JsonNode.class); byte[] serialized = getFormat().withForceJsonDataToBase64().serialize(input); @@ -124,7 +136,7 @@ void deserializeWithInvalidExtensionName(String inputFile, CloudEvent output) { @ParameterizedTest @MethodSource("roundTripTestArguments") - void jsonRoundTrip(String inputFile) throws IOException { + void jsonRoundTrip(String inputFile) { byte[] input = loadFile(inputFile); JsonNode jsonInput = mapper.readTree(input); @@ -156,7 +168,7 @@ void throwExpectedOnInvalidSpecversion() { @ParameterizedTest @MethodSource("badJsonContent") - /** + /* * JSON content that should fail deserialization * as it represents content that is not CE * specification compliant. @@ -328,7 +340,7 @@ private static byte[] loadFile(String input) { private static CloudEvent normalizeToJsonValueIfNeeded(CloudEvent event) { if (event.getData() != null && JsonFormat.dataIsJsonContentType(event.getDataContentType())) { - CloudEventBuilder builder = null; + CloudEventBuilder builder; if (event.getSpecVersion() == SpecVersion.V1) { builder = CloudEventBuilder.v1(event); } else { diff --git a/formats/json-jackson/src/test/java/io/cloudevents/jackson/PojoCloudEventDataMapperTest.java b/formats/json-jackson/src/test/java/io/cloudevents/jackson/PojoCloudEventDataMapperTest.java index 24e2c25f6..37483f110 100644 --- a/formats/json-jackson/src/test/java/io/cloudevents/jackson/PojoCloudEventDataMapperTest.java +++ b/formats/json-jackson/src/test/java/io/cloudevents/jackson/PojoCloudEventDataMapperTest.java @@ -1,9 +1,5 @@ package io.cloudevents.jackson; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; import io.cloudevents.CloudEvent; import io.cloudevents.core.CloudEventUtils; import io.cloudevents.core.builder.CloudEventBuilder; @@ -12,13 +8,17 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import tools.jackson.core.type.TypeReference; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.json.JsonMapper; +import tools.jackson.databind.node.JsonNodeFactory; import java.nio.charset.StandardCharsets; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -public class PojoCloudEventDataMapperTest { +class PojoCloudEventDataMapperTest { private final JsonNode myPojoJson = JsonNodeFactory.instance.objectNode().put("a", 10).put("b", "Hello World!"); private final String myPojoSerialized = myPojoJson.toString(); @@ -26,8 +26,7 @@ public class PojoCloudEventDataMapperTest { @ParameterizedTest @MethodSource("getPojoMappers") - public void testWithBytes(PojoCloudEventDataMapper mapper) { - + void testWithBytes(PojoCloudEventDataMapper mapper) { CloudEvent event = CloudEventBuilder.v1(Data.V1_MIN) .withData("application/json", myPojoSerialized.getBytes(StandardCharsets.UTF_8)) .build(); @@ -44,8 +43,7 @@ public void testWithBytes(PojoCloudEventDataMapper mapper) { @ParameterizedTest @MethodSource("getPojoMappers") - public void testWithJson(PojoCloudEventDataMapper mapper) { - + void testWithJson(PojoCloudEventDataMapper mapper) { CloudEvent event = CloudEventBuilder.v1(Data.V1_MIN) .withData("application/json", JsonCloudEventData.wrap(myPojoJson)) .build(); @@ -61,7 +59,7 @@ public void testWithJson(PojoCloudEventDataMapper mapper) { } private static Stream getPojoMappers() { - final ObjectMapper objectMapper = new ObjectMapper(); + final JsonMapper objectMapper = new JsonMapper(); return Stream.of( Arguments.of(PojoCloudEventDataMapper.from(objectMapper, new TypeReference() {})), Arguments.of(PojoCloudEventDataMapper.from(objectMapper, MyPojo.class)) diff --git a/formats/protobuf/pom.xml b/formats/protobuf/pom.xml index 3a19031cd..9fd92c68c 100644 --- a/formats/protobuf/pom.xml +++ b/formats/protobuf/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT ../../pom.xml diff --git a/formats/xml/pom.xml b/formats/xml/pom.xml index 057de70e2..ddd27e3a6 100644 --- a/formats/xml/pom.xml +++ b/formats/xml/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT ../../pom.xml diff --git a/http/basic/pom.xml b/http/basic/pom.xml index ab747409e..a6696cd45 100644 --- a/http/basic/pom.xml +++ b/http/basic/pom.xml @@ -21,7 +21,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT ../../pom.xml diff --git a/http/restful-ws-integration-tests/restful-ws-spring/pom.xml b/http/integration-tests/pom.xml similarity index 60% rename from http/restful-ws-integration-tests/restful-ws-spring/pom.xml rename to http/integration-tests/pom.xml index 5832ab7aa..2e4990dcb 100644 --- a/http/restful-ws-integration-tests/restful-ws-spring/pom.xml +++ b/http/integration-tests/pom.xml @@ -20,21 +20,22 @@ 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"> - cloudevents-http-restful-ws-integration-tests + cloudevents-parent io.cloudevents - 4.1.0-SNAPSHOT - ../ + 5.0.0-SNAPSHOT + ../../pom.xml 4.0.0 - cloudevents-http-restful-ws-integration-tests-spring - CloudEvents - JAX-RS Integration Tests - Spring + cloudevents-integration-tests + CloudEvents - Spring Http Integration Tests jar - io.cloudevents.jaxrs.integration.tests.spring - 2.3.2.RELEASE - 5.2.9.RELEASE + + true + 4.0.0 + 7.0.2 @@ -50,32 +51,44 @@ - io.cloudevents - cloudevents-http-restful-ws-integration-tests-common + cloudevents-core + tests + test-jar + ${project.version} + test + + + io.cloudevents + cloudevents-http-basic + ${project.version} + test + + + io.cloudevents + cloudevents-spring + ${project.version} + test + + + io.cloudevents + cloudevents-json-jackson ${project.version} test - org.springframework.boot - spring-boot-starter-jersey + spring-boot-starter-test ${spring-boot.version} test org.springframework.boot - spring-boot-starter-test + spring-boot-starter-web ${spring-boot.version} test - - - org.junit.vintage - junit-vintage-engine - - - + diff --git a/http/integration-tests/src/test/java/io/cloudevents/http/restful/ws/spring/TestApplication.java b/http/integration-tests/src/test/java/io/cloudevents/http/restful/ws/spring/TestApplication.java new file mode 100644 index 000000000..6237bc2c5 --- /dev/null +++ b/http/integration-tests/src/test/java/io/cloudevents/http/restful/ws/spring/TestApplication.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018-Present The CloudEvents 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 + *

+ * http://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.cloudevents.http.restful.ws.spring; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.test.Data; +import io.cloudevents.spring.mvc.CloudEventHttpMessageConverter; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.HttpMessageConverters; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@SpringBootApplication(scanBasePackages = {"io.cloudevents.http.restful.ws"}) +public class TestApplication extends SpringBootServletInitializer { + @Configuration + public static class WebConfig implements WebMvcConfigurer { + @Override + public void configureMessageConverters(HttpMessageConverters.ServerBuilder builder) { + builder.addCustomConverter(new CloudEventHttpMessageConverter()); + } + } + + @RestController + public static class TestResource { + @GetMapping("/getMinEvent") + public CloudEvent getMinEvent() { + return Data.V1_MIN; + } + + @GetMapping(path = "/getStructuredEventCsv", produces = "application/cloudevents+csv") + public CloudEvent getStructuredEventCsv() { + return Data.V1_MIN; + } + + @GetMapping(path = "/getStructuredEventJson", produces = "application/cloudevents+json") + public CloudEvent getStructuredEventJson() { + return Data.V1_MIN; + } + + @GetMapping(value = "/getEvent") + public CloudEvent getEvent() { + return Data.V1_WITH_JSON_DATA_WITH_EXT_STRING; + } + + @PostMapping("/postEventWithoutBody") + public void postEventWithoutBody(@RequestBody CloudEvent inputEvent) { + if (!inputEvent.equals(Data.V1_MIN)) { + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + } +} diff --git a/http/integration-tests/src/test/java/io/cloudevents/http/restful/ws/spring/TestSpringBootMvc.java b/http/integration-tests/src/test/java/io/cloudevents/http/restful/ws/spring/TestSpringBootMvc.java new file mode 100644 index 000000000..aa7e904cd --- /dev/null +++ b/http/integration-tests/src/test/java/io/cloudevents/http/restful/ws/spring/TestSpringBootMvc.java @@ -0,0 +1,119 @@ +/* + * Copyright 2018-Present The CloudEvents 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 + *

+ * http://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.cloudevents.http.restful.ws.spring; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.mock.CSVFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.core.test.Data; +import io.cloudevents.jackson.JsonFormat; +import io.cloudevents.spring.mvc.CloudEventHttpMessageConverter; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.RestClient; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class TestSpringBootMvc { + @LocalServerPort + private int port; + private RestClient target; + + @BeforeEach + void beforeEach() { + target = RestClient.builder() + .configureMessageConverters(builder -> builder.addCustomConverter(new CloudEventHttpMessageConverter())) + .baseUrl(String.format("http://localhost:%d/", port)) + .build(); + } + + @BeforeAll + static void beforeAll() { + EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); + EventFormatProvider.getInstance().registerFormat(new JsonFormat()); + } + + @Test + void contextLoads() { + } + + @Test + void getMinEvent() { + ResponseEntity res = target.get().uri("getMinEvent").retrieve().toEntity(byte[].class); + + assertThat(res.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(res.getHeaders().toSingleValueMap()).containsEntry("ce-specversion", "1.0"); + } + + @Test + void getStructuredEventCsv() { + ResponseEntity res = target.get().uri("getStructuredEventCsv").retrieve().toEntity(CloudEvent.class); + + assertThat(res.getBody()).isEqualTo(Data.V1_MIN); + assertThat(res.getHeaders().getContentType()).isEqualTo(MediaType.valueOf(CSVFormat.INSTANCE.serializedContentType())); + } + + @Test + void getStructuredEventJson() { + ResponseEntity res = target.get().uri("getStructuredEventJson").retrieve().toEntity(CloudEvent.class); + + assertThat(res.getBody()).isEqualTo(Data.V1_MIN); + assertThat(res.getHeaders().getContentType()).isEqualTo(MediaType.valueOf(JsonFormat.CONTENT_TYPE)); + } + + @Test + void getEvent() { + ResponseEntity res = target.get().uri("getEvent").retrieve().toEntity(CloudEvent.class); + + assertThat(res.getBody()).isEqualTo(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING); + } + + @Test + void postEventStructuredCsv() { + ResponseEntity res = target.post() + .uri("postEventWithoutBody") + .contentType(MediaType.valueOf("application/cloudevents+csv")) + .body(Data.V1_MIN) + .retrieve() + .toBodilessEntity(); + + assertThat(res.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + void postEventStructuredJson() { + ResponseEntity res = target.post() + .uri("postEventWithoutBody") + .contentType(MediaType.valueOf("application/cloudevents+json")) + .body(Data.V1_MIN) + .retrieve() + .toBodilessEntity(); + + assertThat(res.getStatusCode()).isEqualTo(HttpStatus.OK); + } +} diff --git a/http/restful-ws-integration-tests/pom.xml b/http/restful-ws-integration-tests/pom.xml deleted file mode 100644 index 56fbb867e..000000000 --- a/http/restful-ws-integration-tests/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - cloudevents-parent - io.cloudevents - 4.1.0-SNAPSHOT - ../../pom.xml - - 4.0.0 - - cloudevents-http-restful-ws-integration-tests - CloudEvents - JAX-RS Web Http Binding Integration Tests - pom - - - - true - - - - restful-ws-common - restful-ws-spring - restful-ws-jersey - restful-ws-resteasy - - - diff --git a/http/restful-ws-integration-tests/restful-ws-common/pom.xml b/http/restful-ws-integration-tests/restful-ws-common/pom.xml deleted file mode 100644 index 32a4335a5..000000000 --- a/http/restful-ws-integration-tests/restful-ws-common/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - cloudevents-http-restful-ws-integration-tests - io.cloudevents - 4.1.0-SNAPSHOT - ../ - - 4.0.0 - - cloudevents-http-restful-ws-integration-tests-common - CloudEvents - JAX-RS Integration Tests - Common - jar - - io.cloudevents.jaxrs.integration.tests.common - - - - - io.cloudevents - cloudevents-http-restful-ws - ${project.version} - - - io.cloudevents - cloudevents-core - tests - test-jar - ${project.version} - - - - org.assertj - assertj-core - ${assertj-core.version} - - - org.junit.jupiter - junit-jupiter - ${junit-jupiter.version} - - - - diff --git a/http/restful-ws-integration-tests/restful-ws-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java b/http/restful-ws-integration-tests/restful-ws-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java deleted file mode 100644 index 2dd181ae8..000000000 --- a/http/restful-ws-integration-tests/restful-ws-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.test.Data; -import org.junit.jupiter.api.Test; - -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response; - -import static org.assertj.core.api.Assertions.assertThat; - -public abstract class BaseTest { - - protected abstract WebTarget getWebTarget(); - - @Test - void getMinEvent() { - Response res = getWebTarget().path("getMinEvent").request().buildGet().invoke(); - - assertThat(res.getHeaderString("ce-specversion")) - .isEqualTo("1.0"); - - CloudEvent outEvent = res.readEntity(CloudEvent.class); - assertThat(outEvent) - .isEqualTo(Data.V1_MIN); - } - - @Test - void getStructuredEvent() { - Response res = getWebTarget().path("getStructuredEvent").request().buildGet().invoke(); - - CloudEvent outEvent = res.readEntity(CloudEvent.class); - assertThat(outEvent) - .isEqualTo(Data.V1_MIN); - assertThat(res.getHeaderString(HttpHeaders.CONTENT_TYPE)) - .isEqualTo(CSVFormat.INSTANCE.serializedContentType()); - } - - @Test - void getEvent() { - Response res = getWebTarget().path("getEvent").request().buildGet().invoke(); - - CloudEvent outEvent = res.readEntity(CloudEvent.class); - assertThat(outEvent) - .isEqualTo(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING); - } - - @Test - void postEventWithoutBody() { - Response res = getWebTarget() - .path("postEventWithoutBody") - .request() - .buildPost(Entity.entity(Data.V1_MIN, CloudEventsProvider.CLOUDEVENT_TYPE)) - .invoke(); - - assertThat(res.getStatus()) - .isEqualTo(200); - } - - @Test - void postEventStructured() { - Response res = getWebTarget() - .path("postEventWithoutBody") - .request() - .buildPost(Entity.entity(Data.V1_MIN, "application/cloudevents+csv")) - .invoke(); - - assertThat(res.getStatus()) - .isEqualTo(200); - } - - @Test - void postEvent() { - Response res = getWebTarget() - .path("postEvent") - .request() - .buildPost(Entity.entity(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING, CloudEventsProvider.CLOUDEVENT_TYPE)) - .invoke(); - - assertThat(res.getStatus()) - .isEqualTo(200); - } -} diff --git a/http/restful-ws-integration-tests/restful-ws-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java b/http/restful-ws-integration-tests/restful-ws-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java deleted file mode 100644 index 212b5b581..000000000 --- a/http/restful-ws-integration-tests/restful-ws-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.test.Data; - -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.core.Response; - -@Path("/") -public class TestResource { - - @GET - @Path("getMinEvent") - public CloudEvent getMinEvent() { - return Data.V1_MIN; - } - - @GET - @Path("getStructuredEvent") - @StructuredEncoding("application/cloudevents+csv") - public CloudEvent getStructuredEvent() { - return Data.V1_MIN; - } - - @GET - @Path("getEvent") - public CloudEvent getEvent() { - return Data.V1_WITH_JSON_DATA_WITH_EXT_STRING; - } - - @POST - @Path("postEventWithoutBody") - public Response postEventWithoutBody(CloudEvent inputEvent) { - if (inputEvent.equals(Data.V1_MIN)) { - return Response.ok().build(); - } - return Response.serverError().build(); - } - - @POST - @Path("postEvent") - public Response postEvent(CloudEvent inputEvent) { - if (inputEvent.equals(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING)) { - return Response.ok().build(); - } - return Response.serverError().build(); - } -} diff --git a/http/restful-ws-integration-tests/restful-ws-jersey/pom.xml b/http/restful-ws-integration-tests/restful-ws-jersey/pom.xml deleted file mode 100644 index 46c817a55..000000000 --- a/http/restful-ws-integration-tests/restful-ws-jersey/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - cloudevents-http-restful-ws-integration-tests - io.cloudevents - 4.1.0-SNAPSHOT - ../ - - 4.0.0 - - cloudevents-http-restful-ws-integration-tests-jersey - CloudEvents - JAX-RS Integration Tests - Jersey - jar - - - 2.30.1 - io.cloudevents.jaxrs.integration.tests.jersey - - - - - - io.cloudevents - cloudevents-http-restful-ws-integration-tests-common - ${project.version} - test - - - - org.glassfish.jersey.test-framework.providers - jersey-test-framework-provider-jetty - ${jersey.version} - test - - - org.glassfish.jersey.inject - jersey-hk2 - ${jersey.version} - test - - - com.github.hanleyt - jersey-junit - 2.2.0 - test - - - - diff --git a/http/restful-ws-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jersey/TestJersey.java b/http/restful-ws-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jersey/TestJersey.java deleted file mode 100644 index 6c17e0505..000000000 --- a/http/restful-ws-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jersey/TestJersey.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.jersey; - -import com.github.hanleyt.JerseyExtension; -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.http.restful.ws.BaseTest; -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import io.cloudevents.http.restful.ws.TestResource; -import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.server.ResourceConfig; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.RegisterExtension; - -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Application; - -public class TestJersey extends BaseTest { - - private WebTarget target; - - @Override - protected WebTarget getWebTarget() { - return target; - } - - @BeforeAll - public static void beforeAll() { - EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); - } - - @BeforeEach - void beforeEach(WebTarget target) { - this.target = target; - } - - @RegisterExtension - JerseyExtension jerseyExtension = new JerseyExtension(this::configureJersey, this::configureJerseyClient); - - private Application configureJersey() { - return new ResourceConfig(TestResource.class) - .register(CloudEventsProvider.class); - } - - private ClientConfig configureJerseyClient(ExtensionContext extensionContext, ClientConfig clientConfig) { - return clientConfig - .register(CloudEventsProvider.class); - } - -} diff --git a/http/restful-ws-integration-tests/restful-ws-resteasy/pom.xml b/http/restful-ws-integration-tests/restful-ws-resteasy/pom.xml deleted file mode 100644 index dc0916cbe..000000000 --- a/http/restful-ws-integration-tests/restful-ws-resteasy/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - cloudevents-http-restful-ws-integration-tests - io.cloudevents - 4.1.0-SNAPSHOT - ../ - - 4.0.0 - - cloudevents-http-restful-ws-integration-tests-resteasy - CloudEvents - JAX-RS Integration Tests - RESTEasy - jar - - - io.cloudevents.jaxrs.integration.tests.resteasy - 3.9.2 - 4.5.6.Final - - - - - - io.cloudevents - cloudevents-http-restful-ws-integration-tests-common - ${project.version} - test - - - - io.vertx - vertx-core - ${vertx.version} - test - - - org.jboss.resteasy - resteasy-vertx - ${resteasy.version} - test - - - - diff --git a/http/restful-ws-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/resteasy/TestResteasy.java b/http/restful-ws-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/resteasy/TestResteasy.java deleted file mode 100644 index cba075146..000000000 --- a/http/restful-ws-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/resteasy/TestResteasy.java +++ /dev/null @@ -1,62 +0,0 @@ - -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.resteasy; - -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.http.restful.ws.BaseTest; -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import io.cloudevents.http.restful.ws.TestResource; -import org.jboss.resteasy.plugins.server.vertx.VertxContainer; -import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment; -import org.jboss.resteasy.test.TestPortProvider; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; - -public class TestResteasy extends BaseTest { - - private static VertxResteasyDeployment resteasyDeployment; - private static WebTarget target; - - @Override - protected WebTarget getWebTarget() { - return target; - } - - @BeforeAll - public static void beforeClass() throws Exception { - EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); - - String base = TestPortProvider.generateBaseUrl(); - TestResteasy.resteasyDeployment = VertxContainer.start(base); - TestResteasy.resteasyDeployment.getProviderFactory().register(CloudEventsProvider.class); - TestResteasy.resteasyDeployment.getRegistry().addPerRequestResource(TestResource.class); - - TestResteasy.target = ClientBuilder.newClient().register(CloudEventsProvider.class).target(base); - } - - @AfterAll - public static void after() throws Exception { - TestResteasy.resteasyDeployment.stop(); - } - -} diff --git a/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/JerseyConfig.java b/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/JerseyConfig.java deleted file mode 100644 index 92cd0c968..000000000 --- a/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/JerseyConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.spring; - -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import io.cloudevents.http.restful.ws.TestResource; -import org.glassfish.jersey.server.ResourceConfig; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class JerseyConfig extends ResourceConfig { - public JerseyConfig() { - registerClasses(CloudEventsProvider.class, TestResource.class); - } -} diff --git a/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/TestApplication.java b/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/TestApplication.java deleted file mode 100644 index 920a3528d..000000000 --- a/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/TestApplication.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.spring; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; - -@SpringBootApplication(scanBasePackages = {"io.cloudevents.http.restful.ws.spring"}) -public class TestApplication extends SpringBootServletInitializer { -} diff --git a/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/TestSpringBootWithJersey.java b/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/TestSpringBootWithJersey.java deleted file mode 100644 index 3f7519ce5..000000000 --- a/http/restful-ws-integration-tests/restful-ws-spring/src/test/java/io/cloudevents/http/restful/ws/spring/TestSpringBootWithJersey.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.spring; - -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.http.restful.ws.BaseTest; -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import java.net.URI; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class TestSpringBootWithJersey extends BaseTest { - - @LocalServerPort - private int port; - - private WebTarget target; - - @Override - protected WebTarget getWebTarget() { - return target; - } - - @BeforeEach - void beforeEach() { - target = ClientBuilder.newClient().register(CloudEventsProvider.class).target(URI.create("http://localhost:" + this.port + "/")); - } - - @BeforeAll - public static void beforeAll() { - EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); - } - - @Test - public void contextLoads() { - } - -} diff --git a/http/restful-ws-jakarta-integration-tests/pom.xml b/http/restful-ws-jakarta-integration-tests/pom.xml deleted file mode 100644 index 1b2918826..000000000 --- a/http/restful-ws-jakarta-integration-tests/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - cloudevents-parent - io.cloudevents - 4.1.0-SNAPSHOT - ../../pom.xml - - 4.0.0 - - cloudevents-http-restful-ws-jakarta-integration-tests - CloudEvents - JAX-RS Jakarta EE9+ Web Http Binding Integration Tests - pom - - - - true - - - - restful-ws-jakarta-common - restful-ws-resteasy - - - restful-ws-liberty - - - diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/pom.xml deleted file mode 100644 index 0b505c069..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - cloudevents-http-restful-ws-jakarta-integration-tests - io.cloudevents - 4.1.0-SNAPSHOT - ../ - - 4.0.0 - cloudevents-http-restful-ws-jakarta-integration-tests-common - CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - Common - jar - - - cloudevents.http.restful.ws.jakarta.integration.tests.common - - - - - io.cloudevents - cloudevents-http-restful-ws-jakarta - ${project.version} - - - io.cloudevents - cloudevents-core - tests - test-jar - ${project.version} - - - org.assertj - assertj-core - ${assertj-core.version} - - - org.junit.jupiter - junit-jupiter - ${junit-jupiter.version} - - - diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java deleted file mode 100644 index ea5cc7569..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.test.Data; -import org.junit.jupiter.api.Test; - -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.Response; - -import static org.assertj.core.api.Assertions.assertThat; - -public abstract class BaseTest { - - protected abstract WebTarget getWebTarget(); - - @Test - void getMinEvent() { - Response res = getWebTarget().path("getMinEvent").request().buildGet().invoke(); - - assertThat(res.getHeaderString("ce-specversion")) - .isEqualTo("1.0"); - - CloudEvent outEvent = res.readEntity(CloudEvent.class); - assertThat(outEvent) - .isEqualTo(Data.V1_MIN); - } - - @Test - void getStructuredEvent() { - Response res = getWebTarget().path("getStructuredEvent").request().buildGet().invoke(); - - CloudEvent outEvent = res.readEntity(CloudEvent.class); - assertThat(outEvent) - .isEqualTo(Data.V1_MIN); - assertThat(res.getHeaderString(HttpHeaders.CONTENT_TYPE)) - .isEqualTo(CSVFormat.INSTANCE.serializedContentType()); - } - - @Test - void getEvent() { - Response res = getWebTarget().path("getEvent").request().buildGet().invoke(); - - CloudEvent outEvent = res.readEntity(CloudEvent.class); - assertThat(outEvent) - .isEqualTo(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING); - } - - @Test - void postEventWithoutBody() { - Response res = getWebTarget() - .path("postEventWithoutBody") - .request() - .buildPost(Entity.entity(Data.V1_MIN, CloudEventsProvider.CLOUDEVENT_TYPE)) - .invoke(); - - assertThat(res.getStatus()) - .isEqualTo(200); - } - - @Test - void postEventStructured() { - Response res = getWebTarget() - .path("postEventWithoutBody") - .request() - .buildPost(Entity.entity(Data.V1_MIN, "application/cloudevents+csv")) - .invoke(); - - assertThat(res.getStatus()) - .isEqualTo(200); - } - - @Test - void postEvent() { - Response res = getWebTarget() - .path("postEvent") - .request() - .buildPost(Entity.entity(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING, CloudEventsProvider.CLOUDEVENT_TYPE)) - .invoke(); - - assertThat(res.getStatus()) - .isEqualTo(200); - } -} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java deleted file mode 100644 index 923a8572d..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.test.Data; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; - -@Path("/") -public class TestResource { - - @GET - @Path("getMinEvent") - public CloudEvent getMinEvent() { - return Data.V1_MIN; - } - - @GET - @Path("getStructuredEvent") - @StructuredEncoding("application/cloudevents+csv") - public CloudEvent getStructuredEvent() { - return Data.V1_MIN; - } - - @GET - @Path("getEvent") - public CloudEvent getEvent() { - return Data.V1_WITH_JSON_DATA_WITH_EXT_STRING; - } - - @POST - @Path("postEventWithoutBody") - public Response postEventWithoutBody(CloudEvent inputEvent) { - if (inputEvent.equals(Data.V1_MIN)) { - return Response.ok().build(); - } - return Response.serverError().build(); - } - - @POST - @Path("postEvent") - public Response postEvent(CloudEvent inputEvent) { - if (inputEvent.equals(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING)) { - return Response.ok().build(); - } - return Response.serverError().build(); - } -} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/pom.xml deleted file mode 100644 index d032e3af3..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - cloudevents-http-restful-ws-jakarta-integration-tests - io.cloudevents - 2.5.0-SNAPSHOT - ../ - - 4.0.0 - - cloudevents-http-restful-ws-jakarta-integration-tests-jersey - CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - Jersey - jar - - - cloudevents.http.restful.ws.jakarta.integration.tests.jersey - 3.0.8 - 3.0.0 - - - - - - io.cloudevents - cloudevents-http-restful-ws-jakarta-integration-tests-common - ${project.version} - test - - - jakarta.ws.rs - jakarta.ws.rs-api - ${jakarta-ee.version} - test - - - org.glassfish.jersey.test-framework.providers - jersey-test-framework-provider-jetty - ${jersey.version} - test - - - org.glassfish.jersey.inject - jersey-hk2 - ${jersey.version} - test - - - org.junit.jupiter - junit-jupiter-api - ${junit-jupiter.version} - test - - - - diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/com/github/hanleyt/JerseyExtension.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/com/github/hanleyt/JerseyExtension.java deleted file mode 100644 index 066535c05..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/com/github/hanleyt/JerseyExtension.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Ported from https://github.com/hanleyt/jersey-junit as no version supports Jesery versions >=3.0.0 - * - * Only update is the replacement of the ws-rs package namespace from javax. to jakarta. - */ - -package com.github.hanleyt; - -import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.test.DeploymentContext; -import org.glassfish.jersey.test.JerseyTest; -import org.glassfish.jersey.test.TestProperties; -import org.glassfish.jersey.test.spi.TestContainerException; -import org.glassfish.jersey.test.spi.TestContainerFactory; -import org.junit.jupiter.api.extension.AfterEachCallback; -import org.junit.jupiter.api.extension.BeforeEachCallback; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolver; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Application; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; - -public class JerseyExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { - - private static final Collection> INJECTABLE_PARAMETER_TYPES = Arrays.asList(Client.class, WebTarget.class, URI.class); - - private final Function testContainerFactoryProvider; - private final Function deploymentContextProvider; - private final BiFunction configProvider; - - private JerseyExtension() { - throw new IllegalStateException("JerseyExtension must be registered programmatically"); - } - - public JerseyExtension(Supplier applicationSupplier) { - this((unused) -> applicationSupplier.get(), null); - } - - public JerseyExtension(Supplier applicationSupplier, - BiFunction configProvider) { - this((unused) -> applicationSupplier.get(), configProvider); - } - - public JerseyExtension(Function applicationProvider) { - this(applicationProvider, null); - } - - public JerseyExtension(Function applicationProvider, - BiFunction configProvider) { - this(null, (context) -> DeploymentContext.builder(applicationProvider.apply(context)).build(), configProvider); - } - - public JerseyExtension(Function testContainerFactoryProvider, - Function deploymentContextProvider, - BiFunction configProvider) { - this.testContainerFactoryProvider = testContainerFactoryProvider; - this.deploymentContextProvider = deploymentContextProvider; - this.configProvider = configProvider; - } - - @Override - public void beforeEach(ExtensionContext context) throws Exception { - JerseyTest jerseyTest = initJerseyTest(context); - getStore(context).put(Client.class, jerseyTest.client()); - getStore(context).put(WebTarget.class, jerseyTest.target()); - getStore(context).put(URI.class, jerseyTest.target().getUri()); - } - - private JerseyTest initJerseyTest(ExtensionContext context) throws Exception { - JerseyTest jerseyTest = new JerseyTest() { - - @Override - protected DeploymentContext configureDeployment() { - forceSet(TestProperties.CONTAINER_PORT, "0"); - return deploymentContextProvider.apply(context); - } - - @Override - protected TestContainerFactory getTestContainerFactory() throws TestContainerException { - if (testContainerFactoryProvider != null) { - return testContainerFactoryProvider.apply(context); - } - return super.getTestContainerFactory(); - } - - @Override - protected void configureClient(ClientConfig config) { - if (configProvider != null) { - config = configProvider.apply(context, config); - } - super.configureClient(config); - } - }; - jerseyTest.setUp(); - getStore(context).put(JerseyTest.class, jerseyTest); - return jerseyTest; - } - - @Override - public void afterEach(ExtensionContext context) throws Exception { - ExtensionContext.Store store = getStore(context); - store.remove(JerseyTest.class, JerseyTest.class).tearDown(); - INJECTABLE_PARAMETER_TYPES.forEach(store::remove); - } - - @Override - public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - Class parameterType = parameterContext.getParameter().getType(); - return INJECTABLE_PARAMETER_TYPES.contains(parameterType); - } - - @Override - public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - Class parameterType = parameterContext.getParameter().getType(); - return getStore(extensionContext).get(parameterType, parameterType); - } - - public static ExtensionContext.Store getStore(ExtensionContext context) { - return context.getStore(ExtensionContext.Namespace.GLOBAL); - } - -} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jakarta/jersey/TestJersey.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jakarta/jersey/TestJersey.java deleted file mode 100644 index fb54c3164..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jakarta/jersey/TestJersey.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.jakarta.jersey; - -import com.github.hanleyt.JerseyExtension; -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.http.restful.ws.BaseTest; -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import io.cloudevents.http.restful.ws.TestResource; -import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.server.ResourceConfig; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.RegisterExtension; - -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Application; - -public class TestJersey extends BaseTest { - - private WebTarget target; - - @Override - protected WebTarget getWebTarget() { - return target; - } - - @BeforeAll - public static void beforeAll() { - EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); - } - - @BeforeEach - void beforeEach(WebTarget target) { - this.target = target; - } - - @RegisterExtension - JerseyExtension jerseyExtension = new JerseyExtension(this::configureJersey, this::configureJerseyClient); - - private Application configureJersey() { - return new ResourceConfig(TestResource.class) - .register(CloudEventsProvider.class); - } - - private ClientConfig configureJerseyClient(ExtensionContext extensionContext, ClientConfig clientConfig) { - return clientConfig - .register(CloudEventsProvider.class); - } - -} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/pom.xml deleted file mode 100644 index 3371c7e69..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/pom.xml +++ /dev/null @@ -1,163 +0,0 @@ - - - - cloudevents-http-restful-ws-jakarta-integration-tests - io.cloudevents - 4.1.0-SNAPSHOT - ../ - - 4.0.0 - - cloudevents-http-restful-ws-jakarta-integration-tests-microprofile - CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - Microprofile and Liberty - war - - - cloudevents.http.restful.ws.jakarta.integration.tests.microprofile - - - 9080 - 9443 - - microprofile-test - - - - - - org.jboss.arquillian - arquillian-bom - 1.6.0.Final - pom - import - - - - - - - - jakarta.platform - jakarta.jakartaee-api - 9.1.0 - provided - - - org.eclipse.microprofile - microprofile - 5.0 - pom - provided - - - io.cloudevents - cloudevents-http-restful-ws-jakarta - ${project.version} - - - io.cloudevents - cloudevents-core - tests - test-jar - ${project.version} - - - org.jboss.resteasy - resteasy-client - 6.0.3.Final - test - - - org.jboss.resteasy - resteasy-json-binding-provider - 6.0.3.Final - test - - - org.glassfish - jakarta.json - 2.0.1 - test - - - - javax.xml.bind - jaxb-api - 2.3.1 - - - javax.activation - activation - 1.1.1 - - - io.openliberty.arquillian - arquillian-liberty-managed-jakarta-junit - 2.1.4 - pom - test - - - org.jboss.shrinkwrap - shrinkwrap-api - test - - - - - ${project.artifactId} - - - org.apache.maven.plugins - maven-war-plugin - 3.3.2 - - pom.xml - - - - org.apache.maven.plugins - maven-failsafe-plugin - 2.22.2 - - - ${arquillian.war.name}.war - - - - - test - - integration-test - - - - - - io.openliberty.tools - liberty-maven-plugin - 3.5.1 - - - - -Dsystem.context.root=/${arquillian.war.name} - - - - - - arquillian-configuration - generate-test-resources - - create - install-feature - configure-arquillian - - - - - - - diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/MpCEApp.java b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/MpCEApp.java deleted file mode 100644 index 279cdb3e4..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/MpCEApp.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.cloudevents.restful.mp.test; - -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -@ApplicationPath("/") -public class MpCEApp extends Application { - -} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/TestResource.java b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/TestResource.java deleted file mode 100644 index 5a73efeb6..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/TestResource.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.cloudevents.restful.mp.test; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.core.test.Data; -import io.cloudevents.http.restful.ws.StructuredEncoding; -import jakarta.annotation.PostConstruct; -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; - -@RequestScoped -@Path("/") -public class TestResource{ - - @PostConstruct - void init() { - EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); - } - - @GET - @Path("getMinEvent") - public CloudEvent getMinEvent() { - return Data.V1_MIN; - } - - @GET - @Path("getStructuredEvent") - @StructuredEncoding("application/cloudevents+csv") - public CloudEvent getStructuredEvent() { - return Data.V1_MIN; - } - - @GET - @Path("getEvent") - public CloudEvent getEvent() { - return Data.V1_WITH_JSON_DATA_WITH_EXT_STRING; - } - - @POST - @Path("postEventWithoutBody") - public Response postEventWithoutBody(CloudEvent inputEvent) { - if (inputEvent.equals(Data.V1_MIN)) { - return Response.ok().build(); - } - return Response.serverError().build(); - } - - @POST - @Path("postEvent") - public Response postEvent(CloudEvent inputEvent) { - if (inputEvent.equals(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING)) { - return Response.ok().build(); - } - return Response.serverError().build(); - } -} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/liberty/config/server.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/liberty/config/server.xml deleted file mode 100644 index 9725cb9c8..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/liberty/config/server.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - microProfile-5.0 - - localConnector-1.0 - servlet-5.0 - - - - - - - - - - diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/test/java/io/cloudevents/http/restful/ws/jakarta/microprofile/TestMicroprofile.java b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/test/java/io/cloudevents/http/restful/ws/jakarta/microprofile/TestMicroprofile.java deleted file mode 100644 index 184fa2c8d..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/test/java/io/cloudevents/http/restful/ws/jakarta/microprofile/TestMicroprofile.java +++ /dev/null @@ -1,123 +0,0 @@ -package io.cloudevents.http.restful.ws.jakarta.microprofile; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.test.Data; -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.Response; -import org.jboss.arquillian.container.test.api.Deployment; -import org.jboss.arquillian.container.test.api.RunAsClient; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.arquillian.test.api.ArquillianResource; -import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.spec.WebArchive; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.URL; - - -/** - * Arquilian does not support assertj, so test cases have been ported to Junit to work with arquilian - */ -@RunWith(Arquillian.class) -public class TestMicroprofile { - - private static final String WARNAME = "microprofile-test.war"; - private Client client = ClientBuilder.newClient(); - - @Deployment(testable = true) - public static WebArchive createDeployment() { - System.out.println(WARNAME); - WebArchive archive = ShrinkWrap.create(WebArchive.class, WARNAME).addPackages(true,"io.cloudevents"); - return archive; - } - - @ArquillianResource - private URL baseURL; - - private WebTarget webTarget; - - public WebTarget getWebTarget() { - if(webTarget == null){ - webTarget = client.target(baseURL.toString()); - webTarget.register(CloudEventsProvider.class); - } - return webTarget; - } - - @Test - @RunAsClient - public void getMinEvent() { - Response res = getWebTarget().path("getMinEvent").request().buildGet().invoke(); - - Assert.assertEquals("1.0",res.getHeaderString("ce-specversion")); - Assert.assertEquals(Data.V1_MIN,res.readEntity(CloudEvent.class)); - - res.close(); - } - - @Test - @RunAsClient - public void getStructuredEvent() { - Response res = getWebTarget().path("getStructuredEvent").request().buildGet().invoke(); - - Assert.assertEquals(Data.V1_MIN,res.readEntity(CloudEvent.class)); - Assert.assertEquals(CSVFormat.INSTANCE.serializedContentType(),res.getHeaderString(HttpHeaders.CONTENT_TYPE)); - - res.close(); - } - - @Test - @RunAsClient - public void testGetEvent() throws Exception { - Response response = getWebTarget().path("getEvent").request().buildGet().invoke(); - - Assert.assertEquals("Valid response code", 200, response.getStatus()); - Assert.assertEquals("should match", Data.V1_WITH_JSON_DATA_WITH_EXT_STRING, response.readEntity(CloudEvent.class)); - - response.close(); - } - - @Test - @RunAsClient - public void postEventWithoutBody() { - Response res = getWebTarget() - .path("postEventWithoutBody") - .request() - .buildPost(Entity.entity(Data.V1_MIN, CloudEventsProvider.CLOUDEVENT_TYPE)) - .invoke(); - - Assert.assertEquals(200,res.getStatus()); - } - - @Test - @RunAsClient - public void postEventStructured() { - Response res = getWebTarget() - .path("postEventWithoutBody") - .request() - .buildPost(Entity.entity(Data.V1_MIN, "application/cloudevents+csv")) - .invoke(); - - Assert.assertEquals(200,res.getStatus()); - } - - @Test - @RunAsClient - public void postEvent() { - Response res = getWebTarget() - .path("postEvent") - .request() - .buildPost(Entity.entity(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING, CloudEventsProvider.CLOUDEVENT_TYPE)) - .invoke(); - - Assert.assertEquals(200,res.getStatus()); - } -} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/pom.xml deleted file mode 100644 index 5b7801412..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - cloudevents-http-restful-ws-jakarta-integration-tests - io.cloudevents - 4.1.0-SNAPSHOT - ../ - - 4.0.0 - - cloudevents-http-restful-ws-jakarta-integration-tests-resteasy - CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - RESTEasy - jar - - - - cloudevents.http.restful.ws.jakarta.integration.tests.resteasy - 4.3.3 - 6.0.3.Final - - - - - - io.cloudevents - cloudevents-http-restful-ws-jakarta-integration-tests-common - ${project.version} - test - - - - io.vertx - vertx-core - ${vertx.version} - test - - - org.jboss.resteasy - resteasy-vertx - ${resteasy.version} - test - - - - - diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/jakarta/resteasy/TestResteasy.java b/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/jakarta/resteasy/TestResteasy.java deleted file mode 100644 index 5cac8fdff..000000000 --- a/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/jakarta/resteasy/TestResteasy.java +++ /dev/null @@ -1,62 +0,0 @@ - -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.jakarta.resteasy; - -import io.cloudevents.core.mock.CSVFormat; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.http.restful.ws.BaseTest; -import io.cloudevents.http.restful.ws.CloudEventsProvider; -import io.cloudevents.http.restful.ws.TestResource; -import org.jboss.resteasy.plugins.server.vertx.VertxContainer; -import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment; -import org.jboss.resteasy.test.TestPortProvider; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.WebTarget; - -public class TestResteasy extends BaseTest { - - private static VertxResteasyDeployment resteasyDeployment; - private static WebTarget target; - - @Override - protected WebTarget getWebTarget() { - return target; - } - - @BeforeAll - public static void beforeClass() throws Exception { - EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); - - String base = TestPortProvider.generateBaseUrl(); - TestResteasy.resteasyDeployment = VertxContainer.start(base); - TestResteasy.resteasyDeployment.getProviderFactory().register(CloudEventsProvider.class); - TestResteasy.resteasyDeployment.getRegistry().addPerRequestResource(TestResource.class); - - TestResteasy.target = ClientBuilder.newClient().register(CloudEventsProvider.class).target(base); - } - - @AfterAll - public static void after() throws Exception { - TestResteasy.resteasyDeployment.stop(); - } - -} diff --git a/http/restful-ws-jakarta/README.md b/http/restful-ws-jakarta/README.md deleted file mode 100644 index 87e63476e..000000000 --- a/http/restful-ws-jakarta/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# HTTP Protocol Binding for Jakarta EE9+ - Jakarta RESTful Web Services - -Javadocs: [![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-http-restful-ws.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-http-restful-ws) - -Documentation: https://cloudevents.github.io/sdk-java/http-jakarta-restful-ws - -The code for this package lies within the [restful-ws](https://github.com/cloudevents/sdk-java/tree/main/http/restful-ws) directory and is copied within here and has `javax.` replaced with `jakarta.` diff --git a/http/restful-ws-jakarta/pom.xml b/http/restful-ws-jakarta/pom.xml deleted file mode 100644 index 3ef8d87a9..000000000 --- a/http/restful-ws-jakarta/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - 4.0.0 - - io.cloudevents - cloudevents-parent - 4.1.0-SNAPSHOT - ../../pom.xml - - - cloudevents-http-restful-ws-jakarta - CloudEvents - Jakarta EE 9+ - Jakarta RESTful Web Services Http Binding - jar - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - default - - true - - - - - - 3.0.0 - 3.0.8 - 4.4.3 - 6.0.3.Final - io.cloudevents.http.restfulws - - - - - io.cloudevents - cloudevents-core - ${project.version} - - - jakarta.ws.rs - jakarta.ws.rs-api - ${jakarta-ee.version} - - - - - - - maven-antrun-plugin - 3.1.0 - - - generate-sources - - - - - - - - - - - - - - - - - - run - - - - - - - - diff --git a/http/restful-ws/README.md b/http/restful-ws/README.md deleted file mode 100644 index 1e6dca297..000000000 --- a/http/restful-ws/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# HTTP Protocol Binding for Jakarta RESTful Web Services - -Javadocs: [![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-http-restful-ws.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-http-restful-ws) - -Documentation: https://cloudevents.github.io/sdk-java/http-jakarta-restful-ws diff --git a/http/restful-ws/pom.xml b/http/restful-ws/pom.xml deleted file mode 100644 index dcec6d0ac..000000000 --- a/http/restful-ws/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - 4.0.0 - - io.cloudevents - cloudevents-parent - 4.1.0-SNAPSHOT - ../../pom.xml - - - cloudevents-http-restful-ws - CloudEvents - Jakarta RESTful Web Services Http Binding - jar - - - 2.1.6 - 2.30.1 - 3.9.0 - 4.5.3.Final - io.cloudevents.http.restfulws - - - - - io.cloudevents - cloudevents-core - ${project.version} - - - jakarta.ws.rs - jakarta.ws.rs-api - ${jakarta-ee.version} - - - - diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/BinaryEncoding.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/BinaryEncoding.java deleted file mode 100644 index 08627f330..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/BinaryEncoding.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotate a method with this annotation to specify that you want to write the returned event - * in binary mode. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface BinaryEncoding { -} diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/CloudEventsProvider.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/CloudEventsProvider.java deleted file mode 100644 index 04a60cac2..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/CloudEventsProvider.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws; - -import io.cloudevents.CloudEvent; -import io.cloudevents.core.format.EventFormat; -import io.cloudevents.core.message.MessageWriter; -import io.cloudevents.core.provider.EventFormatProvider; -import io.cloudevents.http.restful.ws.impl.RestfulWSClientMessageWriter; -import io.cloudevents.http.restful.ws.impl.RestfulWSMessageFactory; -import io.cloudevents.http.restful.ws.impl.RestfulWSMessageWriter; -import io.cloudevents.rw.CloudEventWriter; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.client.ClientRequestContext; -import javax.ws.rs.client.ClientRequestFilter; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyReader; -import javax.ws.rs.ext.MessageBodyWriter; -import javax.ws.rs.ext.Provider; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.Optional; - -/** - * This provider implements {@link CloudEvent} encoding and decoding for Jax-Rs Resources and with {@link javax.ws.rs.client.Client}. - */ -@Provider -@Consumes(MediaType.WILDCARD) -@Produces(MediaType.WILDCARD) -public class CloudEventsProvider implements MessageBodyReader, MessageBodyWriter, ClientRequestFilter { - - /** - * The content type to use when sending {@link CloudEvent} with {@link javax.ws.rs.client.Client} - */ - public static MediaType CLOUDEVENT_TYPE = MediaType.valueOf("application/cloudevents"); - - @Override - public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return CloudEvent.class.isAssignableFrom(type); - } - - @Override - public CloudEvent readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { - return RestfulWSMessageFactory.create(mediaType, httpHeaders, bufferBodyInput(entityStream)).toEvent(); - } - - private byte[] bufferBodyInput(InputStream inputStream) throws IOException { - if (inputStream == null) { - return null; - } - - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - int nRead; - byte[] data = new byte[1024]; - while ((nRead = inputStream.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } - - buffer.flush(); - return buffer.toByteArray(); - } - - @Override - public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return CloudEvent.class.isAssignableFrom(type); - } - - @Override - public void writeTo(CloudEvent event, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { - Optional structuredEncodingFormat = Arrays - .stream(annotations) - .filter(a -> a.annotationType().equals(StructuredEncoding.class)) - .map(a -> ((StructuredEncoding) a).value()) - .findFirst(); - - if (structuredEncodingFormat.isPresent()) { - writeStructured( - event, - structuredEncodingFormat.get(), - new RestfulWSMessageWriter(httpHeaders, entityStream) - ); - } else { - writeBinary( - event, - new RestfulWSMessageWriter(httpHeaders, entityStream) - ); - } - } - - private & CloudEventWriter> void writeBinary(CloudEvent input, V visitor) { - visitor.writeBinary(input); - } - - private & CloudEventWriter> void writeStructured(CloudEvent input, EventFormat format, V visitor) { - visitor.writeStructured(input, format); - } - - private & CloudEventWriter> void writeStructured(CloudEvent input, String formatString, V visitor) { - EventFormat format = EventFormatProvider.getInstance().resolveFormat(formatString); - - if (format == null) { - throw new IllegalArgumentException("Cannot resolve format " + formatString); - } - - writeStructured(input, format, visitor); - } - - @Override - public void filter(ClientRequestContext requestContext) throws IOException { - if (isCloudEventEntity(requestContext.getEntity())) { - EventFormat format = EventFormatProvider.getInstance().resolveFormat(requestContext.getMediaType().toString()); - - if (format != null) { - writeStructured( - (CloudEvent) requestContext.getEntity(), - format, - new RestfulWSClientMessageWriter(requestContext) - ); - } else { - writeBinary( - (CloudEvent) requestContext.getEntity(), - new RestfulWSClientMessageWriter(requestContext) - ); - } - } - } - - private static boolean isCloudEventEntity(Object obj) { - return obj != null && CloudEvent.class.isAssignableFrom(obj.getClass()); - } - -} diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/StructuredEncoding.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/StructuredEncoding.java deleted file mode 100644 index 0e98a8fe8..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/StructuredEncoding.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotate a method with this annotation to specify that you want to write the returned event - * in structured mode. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface StructuredEncoding { - /** - * Specify the content type of the structured mode. - * This values will be used to resolve the {@link io.cloudevents.core.format.EventFormat} through - * the {@link io.cloudevents.core.provider.EventFormatProvider}. - */ - String value(); -} diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/BinaryRestfulWSMessageReaderImpl.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/BinaryRestfulWSMessageReaderImpl.java deleted file mode 100644 index 15453e495..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/BinaryRestfulWSMessageReaderImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.impl; - -import io.cloudevents.SpecVersion; -import io.cloudevents.core.data.BytesCloudEventData; -import io.cloudevents.core.impl.StringUtils; -import io.cloudevents.core.message.impl.BaseGenericBinaryMessageReaderImpl; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MultivaluedMap; -import java.util.Objects; -import java.util.function.BiConsumer; - -import static io.cloudevents.http.restful.ws.impl.CloudEventsHeaders.CE_PREFIX; - -public final class BinaryRestfulWSMessageReaderImpl extends BaseGenericBinaryMessageReaderImpl { - - private final MultivaluedMap headers; - - public BinaryRestfulWSMessageReaderImpl(SpecVersion version, MultivaluedMap headers, byte[] body) { - super(version, body != null && body.length > 0 ? BytesCloudEventData.wrap(body) : null); - - Objects.requireNonNull(headers); - this.headers = headers; - } - - @Override - protected boolean isContentTypeHeader(String key) { - return key.equalsIgnoreCase(HttpHeaders.CONTENT_TYPE); - } - - @Override - protected boolean isCloudEventsHeader(String key) { - return key.length() > CE_PREFIX.length() && StringUtils.startsWithIgnoreCase(key, CE_PREFIX); - } - - @Override - protected String toCloudEventsKey(String key) { - return key.substring(CE_PREFIX.length()).toLowerCase(); - } - - @Override - protected void forEachHeader(BiConsumer fn) { - this.headers.forEach((k, v) -> fn.accept(k, v.get(0))); - } - - @Override - protected String toCloudEventsValue(String value) { - return value; - } -} diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/CloudEventsHeaders.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/CloudEventsHeaders.java deleted file mode 100644 index 09128567f..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/CloudEventsHeaders.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.impl; - -import io.cloudevents.core.message.impl.MessageUtils; - -import javax.ws.rs.core.HttpHeaders; -import java.util.Map; - -class CloudEventsHeaders { - - static final String CE_PREFIX = "ce-"; - - static final Map ATTRIBUTES_TO_HEADERS = MessageUtils.generateAttributesToHeadersMapping(v -> { - if (v.equals("datacontenttype")) { - return HttpHeaders.CONTENT_TYPE; - } - return CE_PREFIX + v; - }); - - static final String SPEC_VERSION = ATTRIBUTES_TO_HEADERS.get("specversion"); - -} diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSClientMessageWriter.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSClientMessageWriter.java deleted file mode 100644 index cfd45ef28..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSClientMessageWriter.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.impl; - -import io.cloudevents.CloudEventData; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.format.EventFormat; -import io.cloudevents.core.message.MessageWriter; -import io.cloudevents.rw.CloudEventRWException; -import io.cloudevents.rw.CloudEventWriter; - -import javax.ws.rs.client.ClientRequestContext; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; - -public final class RestfulWSClientMessageWriter implements CloudEventWriter, MessageWriter { - - private final ClientRequestContext context; - - public RestfulWSClientMessageWriter(ClientRequestContext context) { - this.context = context; - - // http headers could contain a content type, so let's remove it - this.context.getHeaders().remove(HttpHeaders.CONTENT_TYPE); - this.context.setEntity(null); - } - - @Override - public RestfulWSClientMessageWriter create(SpecVersion version) { - this.context.getHeaders().add(CloudEventsHeaders.SPEC_VERSION, version.toString()); - return this; - } - - @Override - public RestfulWSClientMessageWriter withContextAttribute(String name, String value) throws CloudEventRWException { - String headerName = CloudEventsHeaders.ATTRIBUTES_TO_HEADERS.get(name); - if (headerName == null) { - headerName = CloudEventsHeaders.CE_PREFIX + name; - } - this.context.getHeaders().add(headerName, value); - return this; - } - - @Override - public Void end(CloudEventData value) throws CloudEventRWException { - this.context.setEntity(value.toBytes()); - return null; - } - - @Override - public Void end() { - return null; - } - - @Override - public Void setEvent(EventFormat format, byte[] value) throws CloudEventRWException { - this.context.setEntity(value, null, MediaType.valueOf(format.serializedContentType())); - return null; - } -} diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSMessageFactory.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSMessageFactory.java deleted file mode 100644 index 73a95904f..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSMessageFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.impl; - -import io.cloudevents.core.message.MessageReader; -import io.cloudevents.core.message.impl.GenericStructuredMessageReader; -import io.cloudevents.core.message.impl.MessageUtils; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; - -public final class RestfulWSMessageFactory { - - private RestfulWSMessageFactory() { - } - - public static MessageReader create(MediaType mediaType, MultivaluedMap headers, byte[] payload) throws IllegalArgumentException { - return MessageUtils.parseStructuredOrBinaryMessage( - () -> headers.getFirst(HttpHeaders.CONTENT_TYPE), - format -> new GenericStructuredMessageReader(format, payload), - () -> headers.getFirst(CloudEventsHeaders.SPEC_VERSION), - sv -> new BinaryRestfulWSMessageReaderImpl(sv, headers, payload) - ); - } - -} diff --git a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSMessageWriter.java b/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSMessageWriter.java deleted file mode 100644 index 1bf21df60..000000000 --- a/http/restful-ws/src/main/java/io/cloudevents/http/restful/ws/impl/RestfulWSMessageWriter.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-Present The CloudEvents 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 - *

- * http://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.cloudevents.http.restful.ws.impl; - -import io.cloudevents.CloudEventData; -import io.cloudevents.SpecVersion; -import io.cloudevents.core.format.EventFormat; -import io.cloudevents.core.message.MessageWriter; -import io.cloudevents.rw.CloudEventRWException; -import io.cloudevents.rw.CloudEventWriter; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MultivaluedMap; -import java.io.IOException; -import java.io.OutputStream; - -public final class RestfulWSMessageWriter implements CloudEventWriter, MessageWriter { - - private final MultivaluedMap httpHeaders; - private final OutputStream entityStream; - - public RestfulWSMessageWriter(MultivaluedMap httpHeaders, OutputStream entityStream) { - this.httpHeaders = httpHeaders; - this.entityStream = entityStream; - - // http headers could contain a content type, so let's remove it - this.httpHeaders.remove(HttpHeaders.CONTENT_TYPE); - } - - @Override - public RestfulWSMessageWriter create(SpecVersion version) { - this.httpHeaders.add(CloudEventsHeaders.SPEC_VERSION, version.toString()); - return this; - } - - @Override - public RestfulWSMessageWriter withContextAttribute(String name, String value) throws CloudEventRWException { - String headerName = CloudEventsHeaders.ATTRIBUTES_TO_HEADERS.get(name); - if (headerName == null) { - headerName = CloudEventsHeaders.CE_PREFIX + name; - } - this.httpHeaders.add(headerName, value); - return this; - } - - @Override - public Void end(CloudEventData value) throws CloudEventRWException { - try { - this.entityStream.write(value.toBytes()); - } catch (IOException e) { - throw CloudEventRWException.newOther(e); - } - return this.end(); - } - - @Override - public Void end() { - try { - this.entityStream.flush(); - } catch (IOException e) { - throw CloudEventRWException.newOther(e); - } - return null; - } - - @Override - public Void setEvent(EventFormat format, byte[] value) throws CloudEventRWException { - this.httpHeaders.add(HttpHeaders.CONTENT_TYPE, format.serializedContentType()); - try { - this.entityStream.write(value); - } catch (IOException e) { - throw CloudEventRWException.newOther(e); - } - return this.end(); - } -} diff --git a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.client.ClientRequestFilter b/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.client.ClientRequestFilter deleted file mode 100644 index d70b7236c..000000000 --- a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.client.ClientRequestFilter +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright 2018-Present The CloudEvents 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 -#

-# http://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. -# - -io.cloudevents.http.restful.ws.CloudEventsProvider diff --git a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyReader b/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyReader deleted file mode 100644 index d70b7236c..000000000 --- a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyReader +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright 2018-Present The CloudEvents 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 -#

-# http://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. -# - -io.cloudevents.http.restful.ws.CloudEventsProvider diff --git a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyWriter b/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyWriter deleted file mode 100644 index d70b7236c..000000000 --- a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyWriter +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright 2018-Present The CloudEvents 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 -#

-# http://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. -# - -io.cloudevents.http.restful.ws.CloudEventsProvider diff --git a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers b/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers deleted file mode 100644 index 2a284a1eb..000000000 --- a/http/restful-ws/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers +++ /dev/null @@ -1 +0,0 @@ -io.cloudevents.http.restful.ws.CloudEventsProvider diff --git a/http/vertx/pom.xml b/http/vertx/pom.xml index f422afab9..0f6cffcd9 100644 --- a/http/vertx/pom.xml +++ b/http/vertx/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT ../../pom.xml diff --git a/kafka/pom.xml b/kafka/pom.xml index 32b9427d8..9fb630737 100644 --- a/kafka/pom.xml +++ b/kafka/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-kafka diff --git a/mvnw b/mvnw index 41c0f0c23..bd8896bf2 100755 --- a/mvnw +++ b/mvnw @@ -19,292 +19,277 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac -fi +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 fi fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" +} - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" done + printf %x\\n $h +} - saveddir=`pwd` +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - M2_HOME=`dirname "$PRG"`/.. +die() { + printf %s\\n "$1" >&2 + exit 1 +} - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" fi -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi +mkdir -p -- "${MAVEN_HOME%/*}" -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; fi -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi fi -########################################################################################## -# End of extension -########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f fi -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd old mode 100644 new mode 100755 index 86115719e..92450f932 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,3 +1,4 @@ +<# : batch portion @REM ---------------------------------------------------------------------------- @REM Licensed to the Apache Software Foundation (ASF) under one @REM or more contributor license agreements. See the NOTICE file @@ -18,165 +19,171 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir +@REM Apache Maven Wrapper startup batch script, version 3.3.4 @REM @REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output @REM ---------------------------------------------------------------------------- -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) ) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml index 79d9cd534..80bba66b1 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT pom CloudEvents @@ -75,8 +75,6 @@ amqp http/basic http/vertx - http/restful-ws - http/restful-ws-jakarta kafka spring sql @@ -85,17 +83,19 @@ - 8 - 8 + 25 + ${java.version} + ${java.version} UTF-8 - 2.22.2 - 0.1.0 + 3.5.4 + 0.2.0 - 3.16.1 - 5.7.0 + 3.27.6 + 6.0.1 + 3.0.3 @@ -169,9 +169,8 @@ https://docs.spring.io/spring-framework/docs/current/javadoc-api/ https://jakarta.ee/specifications/platform/8/apidocs/ https://kafka.apache.org/30/javadoc/ - https://fasterxml.github.io/jackson-databind/javadoc/2.10/ - 8 + 25 @@ -212,8 +211,7 @@ benchmarks - http/restful-ws-integration-tests - http/restful-ws-jakarta-integration-tests + http/integration-tests examples diff --git a/rocketmq/pom.xml b/rocketmq/pom.xml index e9d182c3a..b70bd6cf8 100644 --- a/rocketmq/pom.xml +++ b/rocketmq/pom.xml @@ -23,7 +23,7 @@ cloudevents-parent io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-rocketmq diff --git a/spring/pom.xml b/spring/pom.xml index 8e6afe0c3..f563123bb 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT cloudevents-spring @@ -32,7 +32,7 @@ io.cloudevents.spring - 2.4.3 + 4.0.0 @@ -107,6 +107,11 @@ spring-boot-starter-web test + + org.springframework.boot + spring-boot-starter-webflux + test + org.springframework.boot spring-boot-starter-test diff --git a/spring/src/main/java/io/cloudevents/spring/http/CloudEventHttpUtils.java b/spring/src/main/java/io/cloudevents/spring/http/CloudEventHttpUtils.java index e8addda99..6c1e603a2 100644 --- a/spring/src/main/java/io/cloudevents/spring/http/CloudEventHttpUtils.java +++ b/spring/src/main/java/io/cloudevents/spring/http/CloudEventHttpUtils.java @@ -27,6 +27,10 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; @@ -52,7 +56,9 @@ private CloudEventHttpUtils() { * @throws CloudEventRWException if something goes wrong while resolving the {@link SpecVersion} or if the message has unknown encoding */ public static MessageReader toReader(HttpHeaders headers, Supplier body) throws CloudEventRWException { - return HttpMessageFactory.createReaderFromMultimap(headers, body.get()); + Map> headersMap = new HashMap<>(); + headers.forEach((key, values) -> headersMap.put(key, new ArrayList<>(values))); + return HttpMessageFactory.createReaderFromMultimap(headersMap, body.get()); } /** diff --git a/spring/src/main/java/io/cloudevents/spring/mvc/CloudEventHttpMessageConverter.java b/spring/src/main/java/io/cloudevents/spring/mvc/CloudEventHttpMessageConverter.java index bee78967d..b6cc7d898 100644 --- a/spring/src/main/java/io/cloudevents/spring/mvc/CloudEventHttpMessageConverter.java +++ b/spring/src/main/java/io/cloudevents/spring/mvc/CloudEventHttpMessageConverter.java @@ -17,6 +17,8 @@ import io.cloudevents.CloudEvent; import io.cloudevents.core.CloudEventUtils; +import io.cloudevents.core.format.EventFormat; +import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.spring.http.CloudEventHttpUtils; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; @@ -37,37 +39,46 @@ * @author Dave Syer */ public class CloudEventHttpMessageConverter extends AbstractHttpMessageConverter { + public CloudEventHttpMessageConverter() { + super(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL); + } - public CloudEventHttpMessageConverter() { - super(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL); - } + @Override + protected boolean supports(Class clazz) { + return CloudEvent.class.isAssignableFrom(clazz); + } - @Override - protected boolean supports(Class clazz) { - return CloudEvent.class.isAssignableFrom(clazz); - } + @Override + protected CloudEvent readInternal(Class clazz, HttpInputMessage inputMessage) + throws IOException, HttpMessageNotReadableException { + byte[] body = StreamUtils.copyToByteArray(inputMessage.getBody()); + return CloudEventHttpUtils.toReader(inputMessage.getHeaders(), () -> body).toEvent(); + } - @Override - protected CloudEvent readInternal(Class clazz, HttpInputMessage inputMessage) - throws IOException, HttpMessageNotReadableException { - byte[] body = StreamUtils.copyToByteArray(inputMessage.getBody()); - return CloudEventHttpUtils.toReader(inputMessage.getHeaders(), () -> body).toEvent(); - } + @Override + protected void writeInternal(CloudEvent event, HttpOutputMessage outputMessage) + throws IOException, HttpMessageNotWritableException { + MediaType contentType = outputMessage.getHeaders().getContentType(); + EventFormat format = contentType != null + ? EventFormatProvider.getInstance().resolveFormat(contentType.toString()) + : null; - @Override - protected void writeInternal(CloudEvent event, HttpOutputMessage outputMessage) - throws IOException, HttpMessageNotWritableException { - CloudEventUtils.toReader(event) - .read(CloudEventHttpUtils.toWriter(outputMessage.getHeaders(), body -> copy(body, outputMessage))); - } - - private void copy(byte[] body, HttpOutputMessage outputMessage) { - try { - StreamUtils.copy(body, outputMessage.getBody()); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } + if (format != null) { + byte[] serialized = format.serialize(event); + StreamUtils.copy(serialized, outputMessage.getBody()); + } else { + CloudEventUtils.toReader(event) + .read(CloudEventHttpUtils.toWriter(outputMessage.getHeaders(), body -> copy(body, outputMessage))); + } + } + private void copy(byte[] body, HttpOutputMessage outputMessage) { + try { + if (body != null && body.length != 0) { + StreamUtils.copy(body, outputMessage.getBody()); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } } diff --git a/spring/src/test/java/io/cloudevents/spring/mvc/MvcRestControllerTests.java b/spring/src/test/java/io/cloudevents/spring/mvc/MvcRestControllerTests.java index 53477b5c7..85ef1bd74 100644 --- a/spring/src/test/java/io/cloudevents/spring/mvc/MvcRestControllerTests.java +++ b/spring/src/test/java/io/cloudevents/spring/mvc/MvcRestControllerTests.java @@ -15,34 +15,33 @@ */ package io.cloudevents.spring.mvc; -import java.net.URI; -import java.util.List; -import java.util.UUID; - import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.spring.http.CloudEventHttpUtils; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverters; +import org.springframework.test.web.servlet.client.ExchangeResult; +import org.springframework.test.web.servlet.client.RestTestClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import java.net.URI; +import java.util.Map; +import java.util.UUID; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -51,93 +50,106 @@ */ @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class MvcRestControllerTests { + private static final String BODY = "{\"value\":\"Dave\"}"; - @Autowired - private TestRestTemplate rest; + private RestTestClient rest; @LocalServerPort private int port; - @Test - void echoWithCorrectHeaders() { - - ResponseEntity response = rest.exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/")) // - .header("ce-id", "12345") // - .header("ce-specversion", "1.0") // - .header("ce-type", "io.spring.event") // - .header("ce-source", "https://spring.io/events") // - .contentType(MediaType.APPLICATION_JSON) // - .body("{\"value\":\"Dave\"}"), String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - // assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); + @BeforeEach + void setUp() { + rest = RestTestClient + .bindToServer() + .baseUrl(String.format("http://localhost:%d/", port)) + .build(); + } + @Test + void echoWithCorrectHeaders() { + ExchangeResult response = rest.post() + .header("ce-id", "12345") // + .header("ce-specversion", "1.0") // + .header("ce-type", "io.spring.event") // + .header("ce-source", "https://spring.io/events") // + .contentType(MediaType.APPLICATION_JSON) // + .body(BODY) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @Test - void structuredRequestResponseEvents() { - - ResponseEntity response = rest - .exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) // - .contentType(new MediaType("application", "cloudevents+json")) // - .body("{" // - + "\"id\":\"12345\"," // - + "\"specversion\":\"1.0\"," // - + "\"type\":\"io.spring.event\"," // - + "\"source\":\"https://spring.io/events\"," // - + "\"data\":{\"value\":\"Dave\"}}"), - String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - // assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + void structuredRequestResponseEvents() { + ExchangeResult response = rest.post() + .uri("event") + .contentType(new MediaType("application", "cloudevents+json")) + .body(String.format( + """ + { + "id": "12345", + "specversion": "1.0", + "type": "io.spring.event", + "source": "https://spring.io/events", + "data": %s + } + """, BODY + )) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @Test void requestResponseEvents() { - - ResponseEntity response = rest - .exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) // - .header("ce-id", "12345") // - .header("ce-specversion", "1.0") // - .header("ce-type", "io.spring.event") // - .header("ce-source", "https://spring.io/events") // - .contentType(MediaType.APPLICATION_JSON) // - .body("{\"value\":\"Dave\"}"), String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + ExchangeResult response = rest.post() + .uri("event") + .header("ce-id", "12345") // + .header("ce-specversion", "1.0") // + .header("ce-type", "io.spring.event") // + .header("ce-source", "https://spring.io/events") // + .contentType(MediaType.APPLICATION_JSON) // + .body(BODY) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @SpringBootApplication @@ -157,51 +169,33 @@ public ResponseEntity echo(@RequestBody Foo foo, @RequestHeader HttpHeaders @PostMapping("/event") public CloudEvent ce(@RequestBody CloudEvent event) { - CloudEvent attributes = CloudEventBuilder.from(event) // + return CloudEventBuilder.from(event) // .withId(UUID.randomUUID().toString()) // .withSource(URI.create("https://spring.io/foos")) // .withType("io.spring.event.Foo") // .withData(event.getData().toBytes()) // .build(); - return attributes; } @Configuration public static class CloudEventHandlerConfiguration implements WebMvcConfigurer { - @Override - public void configureMessageConverters(List> converters) { - converters.add(0, new CloudEventHttpMessageConverter()); + public void configureMessageConverters(HttpMessageConverters.ServerBuilder builder) { + builder.addCustomConverter(new CloudEventHttpMessageConverter()); } - } - } -} - -class Foo { + static class Foo { + private String value; - private String value; - - public Foo() { - } - - public Foo(String value) { - this.value = value; - } - - public String getValue() { - return this.value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public String toString() { - return "Foo [value=" + this.value + "]"; - } + public String getValue() { + return this.value; + } + @Override + public String toString() { + return "Foo [value=" + this.value + "]"; + } + } } diff --git a/spring/src/test/java/io/cloudevents/spring/webflux/WebFluxRestControllerTests.java b/spring/src/test/java/io/cloudevents/spring/webflux/WebFluxRestControllerTests.java index 33ec82689..417e7d7da 100644 --- a/spring/src/test/java/io/cloudevents/spring/webflux/WebFluxRestControllerTests.java +++ b/spring/src/test/java/io/cloudevents/spring/webflux/WebFluxRestControllerTests.java @@ -15,33 +15,33 @@ */ package io.cloudevents.spring.webflux; -import java.net.URI; -import java.util.UUID; - import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.spring.http.CloudEventHttpUtils; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.codec.CodecCustomizer; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; -import org.springframework.http.codec.CodecConfigurer; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.test.web.servlet.client.ExchangeResult; +import org.springframework.test.web.servlet.client.RestTestClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.config.WebFluxConfigurer; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.Map; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -51,93 +51,105 @@ */ @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=REACTIVE") class WebFluxRestControllerTests { + private static final String BODY = "{\"value\":\"Dave\"}"; - @Autowired - private TestRestTemplate rest; + private RestTestClient rest; @LocalServerPort private int port; + @BeforeEach + void setUp() { + rest = RestTestClient + .bindToServer() + .baseUrl(String.format("http://localhost:%d/", port)) + .build(); + } + @Test void echoWithCorrectHeaders() { - - ResponseEntity response = rest.exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/")) // - .header("ce-id", "12345") // - .header("ce-specversion", "1.0") // - .header("ce-type", "io.spring.event") // - .header("ce-source", "https://spring.io/events") // - .contentType(MediaType.APPLICATION_JSON) // - .body("{\"value\":\"Dave\"}"), String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - // assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + ExchangeResult response = rest.post() + .header("ce-id", "12345") // + .header("ce-specversion", "1.0") // + .header("ce-type", "io.spring.event") // + .header("ce-source", "https://spring.io/events") // + .contentType(MediaType.APPLICATION_JSON) // + .body(BODY) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @Test void structuredRequestResponseEvents() { - - ResponseEntity response = rest - .exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) // - .contentType(new MediaType("application", "cloudevents+json")) // - .body("{" // - + "\"id\":\"12345\"," // - + "\"specversion\":\"1.0\"," // - + "\"type\":\"io.spring.event\"," // - + "\"source\":\"https://spring.io/events\"," // - + "\"data\":{\"value\":\"Dave\"}}"), - String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + ExchangeResult response = rest.post() + .uri("event") + .contentType(new MediaType("application", "cloudevents+json")) // + .body(String.format( + """ + { + "id": "12345", + "specversion": "1.0", + "type": "io.spring.event", + "source": "https://spring.io/events", + "data": %s + } + """, BODY + )) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @Test void requestResponseEvents() { - - ResponseEntity response = rest - .exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) // - .header("ce-id", "12345") // - .header("ce-specversion", "1.0") // - .header("ce-type", "io.spring.event") // - .header("ce-source", "https://spring.io/events") // - .contentType(MediaType.APPLICATION_JSON) // - .body("{\"value\":\"Dave\"}"), String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}"); - - HttpHeaders headers = response.getHeaders(); - - assertThat(headers).containsKey("ce-id"); - assertThat(headers).containsKey("ce-source"); - assertThat(headers).containsKey("ce-type"); - - assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345"); - assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo"); - assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos"); - + ExchangeResult response = rest.post() + .uri("event") + .header("ce-id", "12345") // + .header("ce-specversion", "1.0") // + .header("ce-type", "io.spring.event") // + .header("ce-source", "https://spring.io/events") // + .contentType(MediaType.APPLICATION_JSON) // + .body(BODY) + .exchange() + .returnResult(String.class); + + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK); + assertThat(response.getResponseBodyContent()).isEqualTo(BODY.getBytes()); + + Map headers = response.getResponseHeaders().toSingleValueMap(); + + assertThat(headers) + .containsKey("ce-id") + .containsKey("ce-source") + .containsKey("ce-type") + .doesNotContainEntry("ce-id", "12345") + .containsEntry("ce-type", "io.spring.event.Foo") + .containsEntry("ce-source", "https://spring.io/foos"); } @SpringBootApplication @@ -160,42 +172,26 @@ public Mono event(@RequestBody Mono body) { } @Configuration - public static class CloudEventHandlerConfiguration implements CodecCustomizer { - - @Override - public void customize(CodecConfigurer configurer) { - configurer.customCodecs().register(new CloudEventHttpMessageReader()); - configurer.customCodecs().register(new CloudEventHttpMessageWriter()); - } - + public static class CloudEventHandlerConfiguration implements WebFluxConfigurer { + @Override + public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { + configurer.customCodecs().register(new CloudEventHttpMessageReader()); + configurer.customCodecs().register(new CloudEventHttpMessageWriter()); + } } } -} + static class Foo { + private String value; -class Foo { + public String getValue() { + return this.value; + } - private String value; - - public Foo() { - } - - public Foo(String value) { - this.value = value; - } - - public String getValue() { - return this.value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public String toString() { - return "Foo [value=" + this.value + "]"; - } - -} \ No newline at end of file + @Override + public String toString() { + return "Foo [value=" + this.value + "]"; + } + } +} diff --git a/sql/pom.xml b/sql/pom.xml index ae8345fa3..6a91718ba 100644 --- a/sql/pom.xml +++ b/sql/pom.xml @@ -5,7 +5,7 @@ cloudevents-parent io.cloudevents - 4.1.0-SNAPSHOT + 5.0.0-SNAPSHOT 4.0.0 @@ -54,9 +54,9 @@ test - com.fasterxml.jackson.dataformat + tools.jackson.dataformat jackson-dataformat-yaml - 2.15.2 + ${jackson.version} test diff --git a/sql/src/test/java/io/cloudevents/sql/TCKTestSuite.java b/sql/src/test/java/io/cloudevents/sql/TCKTestSuite.java index 3a5a16b89..8befc7d3d 100644 --- a/sql/src/test/java/io/cloudevents/sql/TCKTestSuite.java +++ b/sql/src/test/java/io/cloudevents/sql/TCKTestSuite.java @@ -1,16 +1,18 @@ package io.cloudevents.sql; import com.fasterxml.jackson.annotation.JsonValue; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.core.test.Data; import io.cloudevents.jackson.JsonFormat; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.dataformat.yaml.YAMLMapper; -import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.AbstractMap; import java.util.List; import java.util.Map; @@ -20,8 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat; -public class TCKTestSuite { - +class TCKTestSuite { public static class TestSuiteModel { public String name; public List tests; @@ -60,14 +61,11 @@ public CloudEvent getTestInputEvent() { if (this.eventOverrides != null) { CloudEventBuilder builder = CloudEventBuilder.from(inputEvent); this.eventOverrides.forEach((k, v) -> { - if (v instanceof String) { - builder.withContextAttribute(k, (String) v); - } else if (v instanceof Boolean) { - builder.withContextAttribute(k, (Boolean) v); - } else if (v instanceof Number) { - builder.withContextAttribute(k, ((Number) v).intValue()); - } else { - throw new IllegalArgumentException("Unexpected event override attribute '" + k + "' type: " + v.getClass()); + switch (v) { + case String s -> builder.withContextAttribute(k, s); + case Boolean b -> builder.withContextAttribute(k, b); + case Number number -> builder.withContextAttribute(k, number.intValue()); + default -> throw new IllegalArgumentException("Unexpected event override attribute '" + k + "' type: " + v.getClass()); } }); inputEvent = builder.build(); @@ -76,26 +74,20 @@ public CloudEvent getTestInputEvent() { } public EvaluationException.ErrorKind getEvaluationExceptionErrorKind() { - switch (this.error) { - case CAST: - return EvaluationException.ErrorKind.CAST; - case MATH: - return EvaluationException.ErrorKind.MATH; - case MISSING_FUNCTION: - return EvaluationException.ErrorKind.MISSING_FUNCTION; - case MISSING_ATTRIBUTE: - return EvaluationException.ErrorKind.MISSING_ATTRIBUTE; - case FUNCTION_EVALUATION: - return EvaluationException.ErrorKind.FUNCTION_EVALUATION; - } - return null; + return switch (this.error) { + case CAST -> EvaluationException.ErrorKind.CAST; + case MATH -> EvaluationException.ErrorKind.MATH; + case MISSING_FUNCTION -> EvaluationException.ErrorKind.MISSING_FUNCTION; + case MISSING_ATTRIBUTE -> EvaluationException.ErrorKind.MISSING_ATTRIBUTE; + case FUNCTION_EVALUATION -> EvaluationException.ErrorKind.FUNCTION_EVALUATION; + default -> null; + }; } } public Stream> tckTestCases() { - ObjectMapper mapper = new YAMLMapper(); - mapper.registerModule(JsonFormat.getCloudEventJacksonModule()); + ObjectMapper mapper = YAMLMapper.builder().addModule(JsonFormat.getCloudEventJacksonModule()).build(); // Files to load Stream tckFiles = Stream.of( @@ -122,10 +114,12 @@ public Stream> tckTestCases() { return tckFiles .map(fileName -> { try { - return mapper.readValue(this.getClass().getResource(fileName), TestSuiteModel.class); - } catch (IOException e) { + Path path = Paths.get(this.getClass().getResource(fileName).toURI()); + return mapper.readValue(path.toFile(), TestSuiteModel.class); + } catch (URISyntaxException e) { throw new RuntimeException(fileName, e); } + }) .filter(Objects::nonNull) .flatMap(m -> m.tests.stream().map(tc -> new AbstractMap.SimpleImmutableEntry<>(m.name + ": " + tc.name, tc))); diff --git a/sql/src/test/java/io/cloudevents/sql/asserts/ResultAssert.java b/sql/src/test/java/io/cloudevents/sql/asserts/ResultAssert.java index 427c1ae1f..1930fc975 100644 --- a/sql/src/test/java/io/cloudevents/sql/asserts/ResultAssert.java +++ b/sql/src/test/java/io/cloudevents/sql/asserts/ResultAssert.java @@ -25,6 +25,7 @@ public IntegerAssert asInteger() { .asInstanceOf(INTEGER); } + @Override public StringAssert asString() { isNotNull(); return (StringAssert) assertThat(this.actual.value()) @@ -53,7 +54,7 @@ public ObjectAssert value() { return assertThat(this.actual.value()); } - public IterableAssert causes() { + public AbstractCollectionAssert> causes() { return assertThat(this.actual.causes()); }