How can I register 'regexp' function in spring data jpa? - spring

I want to use the regexp function(in mysql) in spring data jpa.
I tried 3 ways that I searched on internet.
findByUriRegex, findByUriMatches, findByUriRegexMatches
Caused by: java.lang.IllegalArgumentException: Unsupported keyword REGEX (1): [MatchesRegex, Matches, Regex]
This keywords are in spring docs, but it doesn't work.
registerFunction
spring:
jpa:
database-platform: com.xxx.config.DBCustomDialect
class DBCustomDialect : MariaDB53Dialect() {
init {
registerFunction(
"REGEXP",
SQLFunctionTemplate(
StandardBasicTypes.BOOLEAN, "?1 REGEXP ?2"
)
)
}
}
class EntityRepository: JpaRepository<Entity, Long> {
#Query(value = "SELECT e FROM Entity e WHERE FUNCTION('REGEXP', e.uri, :regex)")
fun findBy(regex: String): List<Entity>
}
But validation failed exception occurred.
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: function (REGEXP) near line 1, column 102
I don't know what I did wrong..
How can I solve it?

I've found solution.
You need to validate SQLFunctionTemplate's return type.
#Query(value = "SELECT e FROM Entity e WHERE FUNCTION('REGEXP', e.uri, :regex)
-> it doesn't work
#Query(value = "SELECT e FROM Entity e WHERE FUNCTION('REGEXP', e.uri, :regex = true)
-> it works

Related

Spring, How to set error message from custom constraint validator at runtime

I have this constraint for validating dhcp host addresses.
annotation class DHCPAddressConstraint(
val message: String = "Invalid dhcp address.",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = [],
val cidrField: String = "",
val addressRangeField: String = ""
)
class DHCPAddressValidator: ConstraintValidator<DHCPAd, Any> {
override fun isValid(obj: Any, context: ConstraintValidatorContext): Boolean {
val cidr = ReflectionUtils.get(obj, cidrField)
val addressRange = ReflectionUtils.get(obj, addressRangeField)
return isValidCIDR(cidr) && isValidAdressRange(cidr, addressRange)
}
}
So if something is invalid it would return just "Invalid dhcp address.". I want to set the error message to be more specific so why is it invalid. For example the dhcp address range may not be in the CIDR range or the user enters reserved IP address and so on. I expect to have error message like this "Invalid dhcp address due to ${reason}". how can I set the constraint error message at runtime?
you could take help of #ControllerAdvice & #ExceptionHandler
Please look at the example code below
#RestControllerAdvice
public class ApiExceptionController {
#ExceptionHandler(value = PageNotFoundApiException.class)
public ResponseEntity<Object> pageNotFoundApiException(PageNotFoundApiException exception){
return new ResponseEntity<>("Page Not Found 404", HttpStatus.NOT_FOUND);
}
}
You can also take a reference over this documentation
I hope, it helps!

Exception with Spring Data Cassandra

I am getting exception while querying cassandra using Spring-Data-Cassandra . Please help
2021-06-01 12:09:48.594 INFO 9568 --- [nio-8080-exec-3] c.e.demo2.Controller.DemoController : Error : org.springframework.data.cassandra.CassandraUncategorizedException: Query; CQL [select * from summary_data where proj_id = ? and category = ? and name = ? and time >= ?]; Query timed out after PT10S; nested exception is com.datastax.oss.driver.api.core.DriverTimeoutException: Query timed out after PT10S
private final AsyncCassandraOperations asyncCassandraTemplate;
public List<Data1> getData(String convProjectId, List<String> stageNames,
String eventCategory, List<String> distinctDateHour) {
final String cql = "select * from summary_data where proj_id = ? and category = ? and name = ? and time >= ?";
List<BanEventLifecycle> bList = new ArrayList<>();
ArrayList<ListenableFuture<List<Data1>>> bFutureList = new ArrayList<>();
distinctDateHour.forEach(dateHr-> stageNames.forEach(stageName->{
ListenableFuture<List<Data1>> futureBData = asyncCassandraTemplate.getAsyncCqlOperations().query(cql,
ps -> ps.bind().setString(0, projectId.toLowerCase()).setString(1,dateHr)
.setString(2, category.toLowerCase()).setString(3, name),
(row, rowNum) -> Data1.getData1(row));
bFutureList.add(futureBData);
}));
bFutureList.forEach(future -> {
try {
banList.addAll(future.get());
} catch (Exception exception) {
}
});
return bList;
}
Spring-Data-Cassandra : 3.0.9.RELEASE
The Java driver for Cassandra throws a DriverTimeoutException when it doesn't get a response back from the coordinator within the driver request timeout which is your case is 10 seconds (PT10S).
You need to review the Cassandra logs to determine why the coordinator didn't respond to driver's request. Either you were executing an expensive query or the cluster was overloaded at the time.
Note that you shouldn't confuse DriverTimeoutException with a ReadTimeoutException which is the error thrown by the coordinator when it hasn't received responses from the replica(s) within the read request timeout. Cheers!

Error executing query in Java code to connect to Presto

We are trying to connect to Presto using Java code and execute some queries. Catalog we are using is MySQL.
Presto is installed on the Linux server. Presto CLI is working fine on Linux. Started Presto in Linux.
MySQL is also installed on the Linux machine. We are able to access MySQL in windows using DbVisualizer.
I created a MySQL connector catalog for Presto. I'm successful in querying data of MySQL using Presto CLI as presto --server localhost:8080 --catalog mysql --schema tutorials.
Executing the Java code on the Windows machine, I'm able to access MySQL and execute queries, but we are unable to query data. When we try to run a query from Presto, it is giving us Error Executing Query. In the below example, I have used a jar from Trinosql
package testdbPresto;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class PrestoJdbc {
public static void main(String args[]) throws SQLException, ClassNotFoundException {
try{
//connect mysql server tutorials database here
Class.forName("com.facebook.presto.jdbc.PrestoDriver");
String url = "jdbc:trino://35.173.241.37:8080/mysql/tutorials";
Properties properties = new Properties();
properties.setProperty("user", "root");
properties.setProperty("password", "Redcar88!");
properties.setProperty("SSL", "true");
Connection connection = DriverManager.getConnection(url, properties);
Statement statement = null;
statement = connection.createStatement();
//select mysql table author table two columns
String sql;
sql = "select auth_id, auth_name from mysql.tutorials.author";
ResultSet resultSet = statement.executeQuery(sql);
//Extract data from result set
while (resultSet.next()) {
//Retrieve by column name
String name = resultSet.getString("auth_name");
//Display values
System.out.println("name : " + name);
}
//Clean-up environment
resultSet.close();
statement.close();
connection.close();
}catch(Exception e){ e.printStackTrace();}
}
}
Output:
java.sql.SQLException: Error executing query
at io.trino.jdbc.TrinoStatement.internalExecute(TrinoStatement.java:274)
at io.trino.jdbc.TrinoStatement.execute(TrinoStatement.java:227)
at io.trino.jdbc.TrinoStatement.executeQuery(TrinoStatement.java:76)
at testdbPresto.PrestoJdbc.main(PrestoJdbc.java:29)
Caused by: java.io.UncheckedIOException: javax.net.ssl.SSLException: Unsupported or unrecognized SSL message
at io.trino.jdbc.$internal.client.JsonResponse.execute(JsonResponse.java:154)
at io.trino.jdbc.$internal.client.StatementClientV1.<init>(StatementClientV1.java:110)
at io.trino.jdbc.$internal.client.StatementClientFactory.newStatementClient(StatementClientFactory.java:24)
at io.trino.jdbc.QueryExecutor.startQuery(QueryExecutor.java:46)
at io.trino.jdbc.TrinoConnection.startQuery(TrinoConnection.java:728)
at io.trino.jdbc.TrinoStatement.internalExecute(TrinoStatement.java:239)
... 3 more
Caused by: javax.net.ssl.SSLException: Unsupported or unrecognized SSL message
at sun.security.ssl.SSLSocketInputRecord.handleUnknownRecord(SSLSocketInputRecord.java:448)
at sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:174)
at sun.security.ssl.SSLTransport.decode(SSLTransport.java:110)
at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1279)
at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1188)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373)
at io.trino.jdbc.$internal.okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:299)
at io.trino.jdbc.$internal.okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:268)
at io.trino.jdbc.$internal.okhttp3.internal.connection.RealConnection.connect(RealConnection.java:160)
at io.trino.jdbc.$internal.okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:256)
at io.trino.jdbc.$internal.okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:134)
at io.trino.jdbc.$internal.okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:113)
at io.trino.jdbc.$internal.okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at io.trino.jdbc.$internal.okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at io.trino.jdbc.$internal.okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at io.trino.jdbc.$internal.okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:125)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at io.trino.jdbc.$internal.client.OkHttpUtil.lambda$basicAuth$1(OkHttpUtil.java:85)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at io.trino.jdbc.$internal.client.OkHttpUtil.lambda$userAgent$0(OkHttpUtil.java:71)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at io.trino.jdbc.$internal.okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at io.trino.jdbc.$internal.okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at io.trino.jdbc.$internal.okhttp3.RealCall.execute(RealCall.java:77)
at io.trino.jdbc.$internal.client.JsonResponse.execute(JsonResponse.java:131)
... 8 more
It is quite old question but it might be still relevant.
You are trying connect to trino with presto jdbc driver. PrestoSQL was rebranded as Trino . So in order to access trino via jdb, you should use trino jdbc driver.
Add trino dependency in your classpath.
If you use maven, add this dependency in the pom.
<dependency>
<groupId>io.trino</groupId>
<artifactId>trino-jdbc</artifactId>
<version>${trino-jdbc.version}</version>
</dependency>
Then use the following driver
Class.forName("io.trino.jdbc.TrinoDriver");
Here is a code that works with Trino.
fun main() {
val trinoUrl = "jdbc:trino://myDomain:443"
val properties = Properties()
properties.setProperty("user", "noUserS")
// properties.setProperty("password", "noPass")
properties.setProperty("SSL", "true")
DriverManager.getConnection(trinoUrl, properties).use { trinoConn ->
trinoConn.createStatement().use { statement ->
statement.connection.catalog = "catalog1"
statement.connection.schema = "default"
println("Executing query...")
statement.executeQuery("""
select
restaurantId,
type,
time
from table1
where time > CURRENT_TIMESTAMP - INTERVAL '1' hour
""".trimIndent()
).use { resultSet ->
val list = mutableListOf<Map<String, String>>()
while (resultSet.next()) {
val data = mapOf(
"restaurantId" to resultSet.getString("restaurantId"),
"type" to resultSet.getString("type"),
"time" to resultSet.getString("time")
)
list.add(data)
}
println("Records returned: ${list.size}")
println(list)
}
}
}
exitProcess(0)
}
It is Kotlin, but it's easy to understand.
The .use {..} it's try-with-resources in Java.
Hope this helps.

Why does a "named query" I'm using in a Processor.process() method not work.? -how can I fixi it?

A "named query" I'm using in a Processor.process() method doesn't work
--Why? -How can I fix it?
thx for any help! :-)
This is the JPA entity with the "named query" in question...
i.e.,
#NamedQuery(name = "ThingTable.byUpdateTs", query = "SELECT e FROM ThingTable e WHERE e.updateTs > :updateTs")
The "named query" is used in the process method code (below), but, is not working...
i.e.,
#Override
public void process(Exchange msg) throws Exception {
String firedTime = msg.getIn().getHeader("firedTime", String.class);
ZonedDateTime zdtnow = ZonedDateTime.parse(firedTime, formatter2);
zdtnow = zdtnow.withZoneSameInstant(ZoneId.of("America/New_York")); // ...in case springboot server defaults to UTC/GMT time zone...
ZonedDateTime startZDT = zdtnow.minusMonths(24); //.minusSeconds(65);
//*********** this is the line of code using the "named query" **********
String pollingQuery="jpa:aaa.bbb.ccc.jar.ThingTable?namedQuery=ThingTable.byUpdateTs&updateTs='" + startZDT.format(formatter) + "'";
msg.getIn().setBody(pollingQuery);
}
The Processor.process() method is used in this camel route...
i.e.,
from("timer://pollingTimer?fixedRate=true&period=60000")
.process(theProcessor::process)
.toD("${body}")
.split(body())
.convertBodyTo(java.lang.String.class, "UTF-8")
.log("===============>>> NEW MESSAGE: ${body}");
a snippet of stacktrace describing error:
i.e.,
-
-
-
2020-12-30 23:53:32.191 ERROR 1 --- [://pollingTimer] o.a.c.p.e.DefaultErrorHandler : Failed delivery for (MessageId: ID-7499dc21186b-1609372412151-0-1 on ExchangeId: ID-7499dc21186b-1609372412151-0-1). Exhausted after delivery attempt: 1 caught: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: jpa://aaa.bbb.ccc.jar.ThingTable?namedQuery=byUpdateTs&updateTs=%272018-12-30+18%3A53%3A31%27 due to: Failed to resolve endpoint: jpa://aaa.bbb.ccc.jar.ThingTable?namedQuery=byUpdateTs&updateTs=%272018-12-30+18%3A53%3A31%27 due to: There are 1 parameters that couldn't be set on the endpoint. Check the uri if the parameters are spelt correctly and that they are properties of the endpoint. Unknown parameters=[{updateTs='2018-12-30 18:53:31'}]
Message History (complete message history is disabled)
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[route1 ] [route1 ] [from[timer://pollingTimer?fixedRate=true&period=60000] ] [ 333]
...
[route1 ] [toD1 ] [${body} ] [ 0]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: jpa://aaa.bbb.ccc.jar.ThingTable?namedQuery=byUpdateTs&updateTs=%272018-12-30+18%3A53%3A31%27 due to: Failed to resolve endpoint: jpa://aaa.bbb.ccc.jar.ThingTable?namedQuery=byUpdateTs&updateTs=%272018-12-30+18%3A53%3A31%27 due to: There are 1 parameters that couldn't be set on the endpoint. Check the uri if the parameters are spelt correctly and that they are properties of the endpoint. Unknown parameters=[{updateTs='2018-12-30 18:53:31'}]
at org.apache.camel.impl.engine.AbstractCamelContext.doGetEndpoint(AbstractCamelContext.java:876) ~[camel-base-3.3.0.jar!/:3.3.0]
at org.apache.camel.impl.engine.AbstractCamelContext.getEndpoint(AbstractCamelContext.java:771) ~[camel-base-3.3.0.jar!/:3.3.0]
at org.apache.camel.support.CamelContextHelper.getMandatoryEndpoint(CamelContextHelper.java:72) ~[camel-support-3.3.0.jar!/:3.3.0]
at org.apache.camel.support.ExchangeHelper.resolveEndpoint(ExchangeHelper.java:114) ~[camel-support-3.3.0.jar!/:3.3.0]
at org.apache.camel.support.ExchangeHelper.resolveEndpoint(ExchangeHelper.java:92) ~[camel-support-3.3.0.jar!/:3.3.0]
at org.apache.camel.processor.SendDynamicProcessor.resolveEndpoint(SendDynamicProcessor.java:287) ~[camel-base-3.3.0.jar!/:3.3.0]
at org.apache.camel.processor.SendDynamicProcessor.process(SendDynamicProcessor.java:155) ~[camel-base-3.3.0.jar!/:3.3.0]
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:395) ~[camel-base-3.3.0.jar!/:3.3.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148) ~[camel-base-3.3.0.jar!/:3.3.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60) ~[camel-base-3.3.0.jar!/:3.3.0]
-
-
-
(Tried apache camel.apache.org website, but, so far, have been unable to find an example "named query" example that uses parameters - like mine, above)
e.g., https://camel.apache.org/components/latest/jpa-component.html)
You have specified the option updateTs which is not a known option for the JPA component.

Grails + hibernate + controller sessionFactory null object?

I am new to using hibernate and grails. I have multiple java objects that I need to persist. To learn how it works I'm using a simple example of an employee class. Its in my src/java with the corresponding xml mappings with it. I think I need to make a session instance from my session factory, and I do not know what I'm doing wrong. I followed a tutorial for setting up hibternate hibernate tut and tried to translate it for grails. Any thoughts?
package com.turingpages.Matrix.view
import org.springframework.dao.DataIntegrityViolationException
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
class MatrixController {
def ctx = AH.application.mainContext
def sessionFactory = ctx.sessionFactory
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
...
def create() {
def session = sessionFactory.currentSession
Transaction tx = null;
Integer employeeID = null;
try{
tx = session.beginTransaction();
Employee employee = new Employee("fname", "lname", 100);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
My stack trace:
ERROR errors.GrailsExceptionResolver - NullPointerException occurred when processing request: [POST] /turingpages/matrix/create
Cannot get property 'currentSession' on null object. Stacktrace follows:
Message: Cannot get property 'currentSession' on null object
Line | Method
->> 33 | create in com.turingpages.Matrix.view.MatrixController$$ENvP7skK
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1110 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 603 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run in java.lang.Thread
There's no reason you should be writing code like that with Grails. If you really need to manage the transaction in a controller, you should do it this way.
def create() {
Integer employeeID = null;
Employee.withTransaction { status ->
Employee employee = new Employee(firstName: "fname", lastName: "lname", noIdea: 100);
employee.save()
if (employee.hasErrors()) {
status.setRollbackOnly()
}
}
return employee.id;
}
That said, when dealing with a single Domain like this, you don't really need to worry about it at all:
def create() {
Employee employee = new Employee(firstName: "fname", lastName: "lname", noIdea: 100);
employee.save(flush: true)
[employee: employee] // generally you want to pass the object back to a view this way
// deal with errors in the domain on the view
}
And even better would be to use a Service class. But that can be your homework assignment.
You need to move the code
def ctx = AH.application.mainContext
def sessionFactory = ctx.sessionFactory
into the method create(), or replace it with
def sessionFactory
However, Grails provides a withTransaction method to serve your purpose in a simpler way:
def create() {
Employee.withTransaction{ status ->
Employee employee = new Employee("fname", "lname", 100).save()
.....
if (employee.id) {
return employee.id
}
else {
status.setRollbackOnly()
}
}
}

Resources