Graphaware TimeTree procedures in unit test using embedded db - java

UPDATE: I found some similar test in neo4j timetree source but using GraphAwareIntegrationTest, which extends ServerIntegrationTest. So I tried creating a GraphDatabaseService Bean for my test with the following, but still no luck. I get "There is no procedure with the name ga.timetree.events.attach registered for this database instance." Is this not possible?
#Bean
public GraphDatabaseService graphDatabaseService() {
GraphDatabaseService gds = new TestGraphDatabaseFactory().newImpermanentDatabaseBuilder().newGraphDatabase();
Procedures procedures = (Procedures)((GraphDatabaseFacade) gds).getDependencyResolver().resolveDependency(Procedures.class);
try {
ClassPathProcedureUtils.registerAllProceduresAndFunctions(procedures);
}catch (Exception ex) {
log.error("error", ex);
}
return gds;
}
=====================
Similar to this issue but I'm using Spring Boot 2, SDN5 with neo4j 3.2.5, graphaware and time tree. I have automatic event attachment setup, and i see events getting saved to the timetree, but I can't query using the procedure call using cypher. I get the error:
Caused by: org.neo4j.ogm.exception.CypherException: Error executing Cypher; Code: Neo.ClientError.Procedure.ProcedureNotFound; Description: There is no procedure with the name `ga.timetree.range` registered for this database instance. Please ensure you've spelled the procedure name correctly and that the procedure is properly deployed.
at org.neo4j.ogm.drivers.embedded.request.EmbeddedRequest.executeRequest(EmbeddedRequest.java:176)
I don't see a TimeTreeProcedures class as answered in the linked issue. Is this still supported in embedded/unit testing?
Also, if it is supported, I would like to use a CustomRootTimeTree. Any help or pointer to cypher that I can define the custom root tree id in the procedure call would also be very much appreciated. Thanks for any help!
Test:
#Test
public void testSingleTimeTree() {
User user = new User("alper#alper.com", "alper", "alper");
userRepository.save(user);
Collection<User> found = userRepository.findByEmail("alper#alper.com");
user = found.iterator().next();
Workout workout = new Workout(new DateTime().plusMonths(2).getMillis());
workoutRepository.save(workout);
GraphUnit.printGraph(graphDb);
Iterable<Workout> workouts = workoutRepository.findWorkouts();
for(Workout workout1 : workouts) {
log.info("workout: {}", workout1);
}
}
Repo (hard coded start/end for now):
public interface WorkoutRepository extends Neo4jRepository<Workout, Long> {
#Query("CALL ga.timetree.range({start: 1506826887000, end: 1512097287, create: false})")
Iterable<Workout> findWorkouts();
}
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-data-releasetrain.version>Kay-RELEASE</spring-data-releasetrain.version>
<!--<neo4j-ogm.version>3.0.0</neo4j-ogm.version>-->
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>${spring-data-releasetrain.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<version>${neo4j-ogm.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>3.2.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- added by me -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
<version>3.2.5</version>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>com.graphaware.neo4j</groupId>
<artifactId>graphaware-framework-embedded</artifactId>
<version>3.2.5.51</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.graphaware.neo4j</groupId>
<artifactId>timetree</artifactId>
<version>3.2.1.51.27</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-graphdb-api</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-io</artifactId>
<version>3.2.5</version>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>com.graphaware.neo4j</groupId>
<artifactId>tests</artifactId>
<version>3.2.5.51</version>
</dependency>
</dependencies>

I was able to finally get it working by debugging into the neo4j source. The tests that test and use Procedures are in https://github.com/graphaware/neo4j-timetree, and it's using ClassPathProcedureUtils class to load classes from target/classes directory. It looks for #Procedure annotations and will process those classes and the Procedures become available. Without modifying that to load classes from jars as well as target/classes, the only way I could get it to work (albeit a hack) is to copy the target/classes output from neo4j-timetree project into my project target/classes output dir.
UPDATE:
I was also able to get it working by just registering the procedures required directly using:
#Bean
public GraphDatabaseService graphDatabaseService() {
GraphDatabaseService gds = new TestGraphDatabaseFactory().newImpermanentDatabaseBuilder().newGraphDatabase();
try {
ClassPathProcedureUtils.registerAllProceduresAndFunctions(procedures);
Procedures procedures = ((GraphDatabaseFacade)gds).getDependencyResolver().resolveDependency(Procedures.class);
procedures.registerProcedure(TimedEventsProcedure.class);
procedures.registerProcedure(TimeTreeProcedure.class);
procedures.registerFunction(TimedEventsProcedure.class);
procedures.registerFunction(TimeTreeProcedure.class);
}catch (Exception ex) {
log.error("error", ex);
}
return gds;
}

Related

Springboot Actuator Refresh does not reload #Value properties in #ConfigurationProperties

I have a springboot application that ingests an application.properties via #ConfigurationProperties and #PropertySource("classpath:application.properties"). My desire is to reload these properties on the fly for the purposes of support. When I POST to http://localhost:8080/actuator/refresh I get a 200 OK response but the body is empty, which I think implies no #RefreshScopes have been refreshed but I'm not sure. I have read and viewed most docs and SO while trying various things but haven't managed to reload a new value.
Here is my app:
application.properties:
# suppress inspection "UnusedProperty" for whole file
# the name of Camel
camel.springboot.name = IntegrationsCamel
# how often to trigger the timer (millis)
myPeriod = 2000
spring.main.allow-bean-definition-overriding=true
# to turn off Camel info in (/actuator/info)
management.info.camel.enabled=false
# to configure logging levels
logging.level.org.springframework = INFO
logging.level.org.apache.camel.spring.boot = INFO
logging.level.org.apache.camel.impl = DEBUG
logging.level.sample.camel = DEBUG
# Environment
integration.env = DEV
spring.application.name = integration
spring.config.import=aws-parameterstore:
# Client API Auth -- Set by Instance
integration.client.auth.key = tempclientkey
integration.client.auth.secret = tempclientsecret
# Client API Credentials -- Set by Instance
integration.client.endpoint = https://127.0.0.2
integration.client.port = 6060
# AWS Paramstore Config
aws.paramstore.enabled=true
aws.paramstore.prefix=/integration
aws.paramstore.defaultContext=application
aws.paramstore.profile-separator=_
# AWS OAuth
cloud.aws.credentials.instance-profile=true
cloud.aws.credentials.profile-name=default
cloud.aws.credentials.access-key=${AWS_ACCESS_KEY_ID}
cloud.aws.credentials.secret-key=${AWS_SECRET_ACCESS_KEY}
# Non EC2 vars (remove when running live)
cloud.aws.stack.auto=false
cloud.aws.region.static=eu-west-1
AWS_EC2_METADATA_DISABLED=true
logging.level.com.amazonaws.util.EC2MetadataUtils=error
logging.level.com.amazonaws.internal.InstanceMetadataServiceResourceFetcher=error
# DB Vars
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://${RDS_HOSTNAME:my-server-domain.com}:${RDS_PORT:1337};databaseName=${RDS_DB_NAME:MYDB}
spring.datasource.username=${RDS_USERNAME:readuser}
spring.datasource.password=${RDS_PASSWORD:${read_pass}}
spring.jpa.properties.hibernate.default_schema=dbo
# Actuator Management
management.endpoints.enabled-by-default=false
management.endpoint.refresh.enabled=true
management.endpoints.web.exposure.include=refresh
All of these are successfully pulled in to the bean
package com.Integration.Configuration;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.EventListener;
#Getter
#Setter
#RefreshScope
#Configuration
public class ApplicationProperties {
#Value("${integration.env}")
private String env;
#Value("${spring.datasource.url}")
private String DB_URL;
#Value("${rds-username}")
private String DB_USERNAME;
#Value("${rds-password}")
private String DB_ENCRYPTED_PASSWORD;
#Value("${oauth2.key}")
private String OAuth2Key;
#Value("${oauth2.secret}")
private String OAuth2Secret;
#Value("${integration.client.endpoint}")
private String ClientAPIEndpoint;
#Value("${integration.client.port}")
private String ClientAPIPort;
#Value("${integration.client.auth.key}")
private String ClientAPIKey;
#Value("${integration.client.auth.secret}")
private String ClientAPISecret;
public ApplicationProperties() {}
#SuppressWarnings("unused")
#EventListener(RefreshScopeRefreshedEvent.class)
public void onRefresh(RefreshScopeRefreshedEvent event) {
// todo: Bug-#01 #RefreshScope actuator/refresh not updating #Values
System.out.println(this.ClientAPIEndpoint);
}
}
The event listener fires without issue too and it will successfully print the value from application.properties. I have debugged main below and all values are populated without issue.
I suspect the issue is here but I'm not sure what I'm doing wrong in main()
package com.Integration;
import com.Integration.AutoLoader.RouteBuilderAutoLoader;
import com.Integration.Configuration.ApplicationProperties;
import com.Integration.Scheduler.TasksScheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.Objects;
#SpringBootApplication
#RefreshScope
#EnableScheduling
public class Integration {
public static String SERVER_ADDR;
protected static CamelContext context;
public static void main(String[] args) throws Exception {
// Spring Boot App Entry
ConfigurableApplicationContext appContext = SpringApplication.run(Integration.class, args);
// Get ApplicationProperties
ApplicationProperties properties = appContext.getBean(ApplicationProperties.class);
SERVER_ADDR = (Objects.equals(properties.getEnv(), "DEV")) ? "0.0.0.0" : "localhost";
// Start Camel Context Engine
context = new DefaultCamelContext();
// Feed Camel our defined routes & start
RouteBuilderAutoLoader.loadRoutes(context);
context.start();
}
}
The last thing I'm unsure of is if I have the necessary dependencies or if I'm missing something here.
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress MavenPackageUpdate -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.Integration</groupId>
<artifactId>Integration</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Integration</name>
<description>Generic API Integration App</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.4.1.jre8</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- AWS/Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws-context</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-starter-aws-parameter-store-config</artifactId>
<version>2.4.0</version>
</dependency>
<!-- Camel 3.14.1 Latest LTS version -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-bom</artifactId>
<version>3.14.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core-languages</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-bean</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-rest</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-direct</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-netty-http</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-platform-http</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-management</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-endpointdsl</artifactId>
<version>3.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-spring</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>4.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
Edit 12/04/2022
Completely redid my classes with #ConfigurationProperties
So when I post to refresh the values in propertySource for AWS automatically update. So eg I change cobaltdlt to cobaltdlttest below, hit refresh, and then I can see the change when I query GET http://localhost:8080/actuator/env
So the refresh is working but it's not reflective in the #Component beans even though the propertySource is updating. In fact the only beans it is working with are the AWS beans.
Have you tried a PropertiesConfiguration bean? See here: https://www.baeldung.com/spring-reloading-properties.
Once configured correctly, it should automatically read changes to your properties file and reload them. Also, there are some limitations that are mentioned in that article that you should be aware of.
#I2obiN. As you have mentioned that ApplicationProperties is getting refreshed by Refresh Scopes, therefore actuator refresh is working properly.
But I noticed that you are using RefreshScope on main application class. IMO this actuator management/refresh will not restart application. You can try to create an extra method that reinitializes Camel Context.
Hope this helps!!
https://www.baeldung.com/java-restart-spring-boot-app#actuators-restart-endpoint
You can invoke the refresh Actuator endpoint by sending an empty HTTP POST to the client's refresh endpoint: http://localhost:8080/actuator/refresh . Then you can confirm it worked by visiting the http://localhost:8080/message endpoint.
And once you refresh, try to rebind immediately by calling the POST endpoint http://localhost:8080/actuator/env
This worked on a spring boot I tried and it reloads the values and you can see it in the stack trace.
I tried doing a field in spring data source with the given payload to Rebind and it reloads Example as the value.
Payload:
{"name":"spring.datasource.userName", "value":"Example"}
In the application.properties, add the following
management.endpoint.env.post.enabled=true
management.endpoint.restart.enabled=true
endpoints.sensitive=true
endpoints.actuator.enabled=true
management.security.enabled=false
management.endpoints.web.exposure.include=*

Swagger #OpenAPIDefinition not doing anything

so I have a simple Spring Boot REST API that works fine, now I have added some swagger dependencies, both for ui and core, and have done some testing with some tags like #ApiIgnore or #Operation and they both work fine and both are updated in the http://localhost:8080/swagger-ui/#/
Now I am trying to update the API info through the #OpenAPIDefinition tag, something like this in my application class:
#OpenAPIDefinition(
info = #Info(
title = "the title",
version = "0.0",
description = "My API",
license = #License(name = "Apache 2.0", url = "http://foo.bar"),
contact = #Contact(url = "http://gigantic-server.com", name = "Fred", email = "Fred#gigagantic-server.com")))
Now I have read here that the spring boot app should do a class scan and recognize the #OpenAPIDefinition bean and update the generated json in http://localhost:8080/v3/api-docs. But this is not the case, I have also tried setting that info with openapi.yaml files but also no luck.
I suspect this might have to do with my dependencies, as I am new to swagger and still a bit lost and might have mixed something up, I leave my pom.xml here:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I am at a bit of a loss on how to continue and don't understand how swagger can recognize the #ApiIgnore tag for example but ignore the #OpenAPIDefinition one. As I said I am new to this whole thing and stackoverflow in general, so please forgive me if I forgot to add any relevant code, thank you!
Try removing some unnecessary dependencies:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
<version>2.1.2</version>
</dependency>
springfox-boot-starter should bring them in already.
If this does not work you can always do the following:
#Configuration
public class SwaggerConfiguration {
#Bean
public OpenAPI openAPI() {
return new OpenAPI()
.info(new Info().title("the title").version("0.0").description("My API")
.contact(new Contact().name("Fred").url("http://gigantic-server.com").email("Fred#gigagantic-server.com")));
}
}
So after a lot of different things I found this guide where it explains how to alter API info, in a nutshell, I added a #Api(tags = "Employee") to my EmployeeController class, then in my Application class added:
#Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(new ApiInfoBuilder()
.title("Employee API")
.description("A CRUD API to demonstrate Springfox 3 integration")
.version("0.0.1-SNAPSHOT")
.license("MIT")
.licenseUrl("https://opensource.org/licenses/MIT")
.build())
.tags(new Tag("Employee", "Endpoints for CRUD operations on employees"))
.select().apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.build();
}
And this appears to solve the issue, I now wonder what would happen if I had multiple controllers, I hope this helps anyone that was in my predicament, the overall issue seemed to be that this is a springfox related way of altering API documentation and the previous ways are swagger-core related? As I said I am new to this world so if anyone could point me out to why it wasn't working it would be amazing, thanks!

Quarkus Reactive - Multiple matching properties for name "security.jaxrs.deny-unannotated-endpoints" Error

Using Quarkus I get the following error at execution time:
Caused by: java.lang.IllegalArgumentException: Multiple matching
properties for name "security.jaxrs.deny-unannotated-endpoints"
property was matched by both public boolean
io.quarkus.resteasy.reactive.common.runtime.JaxRsSecurityConfig.denyJaxRs
and public boolean
io.quarkus.resteasy.runtime.JaxRsSecurityConfig.denyJaxRs. This is
likely because you have an incompatible combination of extensions that
both define the same properties (e.g. including both reactive and
blocking database extensions)
My pom properties are:
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus-plugin.version>1.13.3.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.13.3.Final</quarkus.platform.version>
And dependencies:
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mutiny</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-mutiny</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-jwt</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-jwt-build</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
I'm just trying to stream using Multi from mutiny and Server Sent Elements:
#GET
#Produces(MediaType.SERVER_SENT_EVENTS)
#RestSseElementType(MediaType.TEXT_PLAIN)
#Path("/stream/{count}/{name}")
public Multi<String> greetingsAsStream(int count, String name) {
return service.greetings(count, name);
}
You have both classic RESTEasy (quarkus-resteasy-jsonb, quarkus-resteasy-mutiny) and RESTEasy Reactive (quarkus-resteasy-reactive). You need to pick one and stick to it.
For example, if you want RESTEasy Reactive, you'd remove quarkus-resteasy-mutiny (no need for extra dependency with RESTEasy Reactive), and replace quarkus-resteasy-jsonb with quarkus-resteasy-reactive-jsonb.
I am facing a similar problem:
java.lang.RuntimeException: java.lang.IllegalArgumentException:
Multiple
matching properties for name "security.jaxrs.deny-unannotated-endpoints"
property was matched by both public boolean
io.quarkus.resteasy.reactive.common.runtime.JaxRsSecurityConfig.denyJaxRs
and
public boolean io.quarkus.resteasy.runtime.JaxRsSecurityConfig.denyJaxRs. This
is likely because you have an incompatible combination of extensions that both
define the same properties (e.g. including both reactive and blocking database
extensions)
I am using Swagger OpenAPIGenerate:
generatorName.set("jaxrs-spec")
Gradle dependencies:
dependencies {
implementation(Libs.quarkus_resteasy){
exclude(group = "io-quarkus", module = "quarkus-resteasy-runtime")
}
implementationList(LibGroups.quarkus_rest_server)
}
Libs.quarkus_resteasy
> val quarkus_resteasy = "io.quarkus:quarkus-resteasy"
LibGroups.quarkus_rest_server
>val quarkus_rest_server = listOf(
> > "io.quarkus:quarkus-vertx",
> > "io.quarkus:quarkus-resteasy-reactive-jackson"
> > //"io.quarkus:quarkus-resteasy-reactive"
> )
After excluding the clashing module, I am still getting the same error.
Any poin

How to validate entity in Spring Boot console application?

I have a Spring Boot console application that uses Spring Data.
I have a simple jpa repository
public interface MyRepository extends JpaRepository<MyEntity, Integer> {
}
and an entity defined like this
import javax.validation.constraints.Min;
// ....
#Entity
#Table(schema = "mySchema", name = "myTable")
public class MyEntity {
// ...
#Column(nullable = false)
#Min(100)
private Integer group;
// ...
}
When I save this entity
myRepository.save(myEntity);
pom:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
</dependency>
</dependencies>
I expect to see a validation error because group is 0 but I don't see any issue and at the database the value of a newly added row is 0. What else do I need to do to enable validation?
Try with import javax.validation.Valid; #Valid
When the target argument fails to pass the validation, Spring Boot throws a MethodArgumentNotValidException exception.
Adding this to pom did the trick
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Spring boot + hikari - dataSource or dataSourceClassName or jdbcUrl is required issue

I get the following error trying to start my Spring application
ERROR 5908 --- [ main] com.zaxxer.hikari.HikariConfig : HikariPool-1 - dataSource or dataSourceClassName or jdbcUrl is required.
My application.properties file looks like this:
spring.datasource.one.jdbc-url = jdbc:postgresql://10.x.x.x:y/sampledb1
spring.datasource.one.username = someuser
spring.datasource.one.password = somepasswd
spring.datasource.one.driver-class-name = org.postgresql.Driver
spring.datasource.two.jdbc-url = jdbc:postgresql://10.x.x.x:z/sampledb2
spring.datasource.two.username = someuser
spring.datasource.two.password = somepassword
spring.datasource.two.driver-class-name = org.postgresql.Driver
And I am using DataSourceBuilder class as below:
#Configuration
public class DataSourceConfig
{
#Bean(name = "one")
#Primary
#ConfigurationProperties(prefix = "spring.datasource.one")
public DataSource dataSource1()
{
return DataSourceBuilder.create().build();
}
#Bean(name = "two")
#ConfigurationProperties(prefix = "spring.datasource.two")
public DataSource dataSource2()
{
return DataSourceBuilder.create().build();
}
}
My pom looks like this.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<avro.version>1.8.2</avro.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<version.powermock>1.6.2</version.powermock>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
</dependencies>
This was working fine earlier, but now causing some issues. And the error occurs intermittently, sometime it starts without error, other times it fails with the error.
I tried solutions suggested in the link .They don't seem to work for me.
Change jdbc-url to jdbcUrl so Hikari can find suitable driver per url.
jdbcUrl
This property directs HikariCP to use "DriverManager-based" configuration. We feel that DataSource-based configuration (above) is superior for a variety of reasons (see below), but for many deployments there is little significant difference. When using this property with "old" drivers, you may also need to set the driverClassName property, but try it first without. Note that if this property is used, you may still use DataSource properties to configure your driver and is in fact recommended over driver parameters specified in the URL itself. Default: none
This error can occur when spring looks for the properties file at the wrong location. For example, when the Java option -Dspring.config.location=... is passed to your application server at startup then your properties file of your deployed application is ignored - even if there is no properties file at spring.config.location, too.

Categories

Resources