Validation failed for query for method public abstract org.springframework.data.domain.Page - spring

I'm trying to implement a function using Page in jpa, but I keep getting an IllegalArgumentException for my Page object I don't quite understand, I know the error says I'm trying to pass something that's not supported, but I can't find exactly why.
Here's my code:
Service
public Page<VolumeMeasurerRegistries> getVolumeMeasurerRegistries(ResquestVolumeMeasurerRegistries resquestVolumeMeasurerRegistries) throws VolumeMeasurerRegisterException {
try {
return volumeMeasurerRegisterRepository.findByEquipmentIdEquipmentAndMeasuredTimeLessThanEqualAndMeasuredTimeGreaterThanEqual(
resquestVolumeMeasurerRegistries.getIdEquipment() != null ? UUID.fromString(resquestVolumeMeasurerRegistries.getIdEquipment()) : null,
format.parse(resquestVolumeMeasurerRegistries.getFilterStartDate()),
format.parse(resquestVolumeMeasurerRegistries.getFilterEndDate()),
PageRequest.of(
resquestVolumeMeasurerRegistries.getVolumeMeasurerRegisterDisplayPage(),
resquestVolumeMeasurerRegistries.getVolumeMeasurerRegisterDisplayAmount()));
} catch (Exception getSomeException) {
//Do something
}
}
And this is my repository function:
public interface VolumeMeasurerRegistriesRepository extends JpaRepository<VolumeMeasurerRegistries, UUID> {
#Query(value = "SELECT vmr FROM VolumeMeasurerRegistries vmr "
+ "WHERE (:idEquipment is null or vmr.Equipment.idEquipment = :idEquipment) "
+ "AND (:startTime is null or vmr.measuredTime >= :startTime) "
+ "AND (:endTime is null or vmr.measuredTime <= :endTime) ", nativeQuery = false)
Page<VolumeMeasurerRegistries> findByEquipmentIdEquipmentAndMeasuredTimeLessThanEqualAndMeasuredTimeGreaterThanEqual(
#Nullable #Param("idEquipment") UUID idEquipment,
#Nullable #Param("startTime") Date startTime,
#Nullable #Param("endTime") Date endTime,
#Nullable Pageable pageable);
}
And the error I get:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'volumeMeasurerRegistriesRepository':
Invocation of init method failed; nested exception is
java.lang.IllegalArgumentException: Validation failed for query for
method public abstract org.springframework.data.domain.Page
mx.ssf.sicom.repositories.VolumeMeasurerRegistriesRepository.findByEquipmentIdEquipmentAndMeasuredTimeLessThanEqualAndMeasuredTimeGreaterThanEqual(java.util.UUID,java.util.Date,java.util.Date,org.springframework.data.domain.Pageable)!

Related

Drools using large RAM for larger rules

We have started using Drools [V 7.55.0.Final]. We have a requirement where we have large number of rules (~100,000) but have few(1-10) facts to process for every API request. A sample of each rule is as follows:
rule "Rule-000000-2627"
when
discountObject: Discount(purchaseSource == "FLIPKART" && customerType == "NEW" && bank == "HDFC" &&
purchaseType == "BNPL" && apparelType == "SHIRT" && price >= 100 && price < 200)
then
discountObject.setDiscount(2);
end
The discount object is as follows:
public class Discount {
private String name;
private String purchaseSource;
private String customerType;
private String bank;
private String purchaseType;
private String apparelType;
private int price;
private int discount;
}
The Drools configuration is as follows:
public class DroolDiscountConfig {
private KieServices kieServices = KieServices.Factory.get();
#Value( "${drool.rule.file}" )
private String droolConfigFile;
private KieFileSystem getKieFileSystem() throws IOException {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
Long startTime = Utility.startTime();
String[] droolFiles = this.droolConfigFile.split(",");
for(String droolFile: droolFiles) {
kieFileSystem.write(ResourceFactory.newFileResource(droolFile));
}
Long elapseTime = Utility.elapsedTime(startTime);
System.out.println("Completed loading drool file " + droolConfigFile + " in " + elapseTime);
return kieFileSystem;
}
#Bean
public KieContainer getKieContainer() throws IOException {
System.out.println("Container created...");
getKieRepository();
Long startTimeKieBuilder = Utility.startTime();
KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem());
kb.buildAll();
System.out.println("Kie builder took " + Utility.elapsedTime(startTimeKieBuilder));
Long startTimeKieModule = Utility.startTime();
KieModule kieModule = kb.getKieModule();
System.out.println("Kie Module generation took " + Utility.elapsedTime(startTimeKieModule));
Long startTimeKieContainer = Utility.startTime();
KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());
System.out.println("KieContainer generation took " + Utility.elapsedTime(startTimeKieContainer));
return kContainer;
}
private void getKieRepository() {
Long startTimeKieRepo = Utility.startTime();
final KieRepository kieRepository = kieServices.getRepository();
kieRepository.addKieModule(new KieModule() {
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
});
System.out.println("KieRepo generation took " + Utility.elapsedTime(startTimeKieRepo));
}
}
The Controller is as follows:
#RestController
public class DiscountController {
#Autowired
private KieContainer kieContainer;
#PostMapping("/discount")
public List<Discount> viewDiscount(#RequestBody List<Discount> discounts) {
StatelessKieSession statelessKieSession = kieContainer.newStatelessKieSession();
statelessKieSession.execute(discounts);
return discounts;
}
}
The rule file (single drl file) is of size 40Mb. Whenever, we are starting a service, it occupies around 5-6Gb of RAM. I checked the memory dump using VisualVM but did not find much detail as most of the memory was occupied by bytes[] and Strings[].
I would like to know, are we using Drools in the right way. How can we avoid this huge memory consumption.
Also there are two other issues we are facing:
The first API request takes long time to respond (around 30 seconds).
The service takes long time to start (around 5mins)
If we try to restrict the size of the VM to around 3-4Gb then we get the following error
ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'discountController': Unsatisfied dependency expressed through field 'kieContainer'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getKieContainer' defined in class path resource
[load/test/DroolDiscountConfig.class]: Bean instantiation via factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.kie.api.runtime.KieContainer]:
Factory method 'getKieContainer' threw exception; nested exception is java.lang.OutOfMemoryError: Java heap space

Parameter with that position [1] did not exist error when using Spring Data native query

I am new to spring boot and spring data jpa. I am trying to use native queries for executing search based on search attributes received from UI.
The records that are obtained based on the searchParam should search if the searchParam is contained in any of the specified columns (as mentioned in the native query)
I have written the following code but I end up receiving the error as mentioned in the title. I have tried looking up for response in stackoverflow. But i believe i have followed the suggestions as mentioned in many of the threads.
Any help in this regard would be highly appreciated.
Code snippet below
EpicController.java
#CrossOrigin
#RequestMapping(value="/search", method = RequestMethod.GET)
public Page<Epic> searchEpicsByProjectIdAndSearchParam(#RequestParam String searchParam, #RequestParam String projectId, Pageable pageable) throws Exception {
logger.info("Inside searchEpicsByAttributes() based on searchQuery API");
Page<Epic> results = null;
try {
results = epicService.searchEpicsByProjectIdAndSearchParam(searchParam, projectId, pageable);
}
catch(Exception ex) {
ex.printStackTrace();
throw new Exception("Exception occurred :: " + ex.getStackTrace());
}
return results;
}
EpicService.java (Interface)
public interface EpicService {
Page<Epic> searchEpicsByProjectIdAndSearchParam(String searchParam, String projectId, Pageable pageable);
}
EpicServiceImpl.java
#Override
public Page<Epic> searchEpicsByProjectIdAndSearchParam(String searchParam, String projectId, Pageable pageable) {
logger.info(" Inside searchEpicsByProjectIdAndSearchParam() API in EpicServiceImpl");
return epicRepository.findBySearchParamsAndProjectId(searchParam,projectId, pageable);
}
EpicRepository.java
#Repository
public interface EpicRepository extends JpaRepository<Issue, String> {
#Query(value =
"select i.* from issue i where ("
+ "upper(i.name) like upper('%?1%'))"
+ "and upper(i.project_id) = upper('%?2%')"
+ "ORDER BY i.name DESC \n-- #pageable\n",
countQuery =
"select count(i.*) from issue i where ("
+ "upper(i.name) like upper('%?1%'))"
+ "and upper(i.project_id) = upper('%?2%')",
nativeQuery = true)
Page<Epic> findBySearchParamsAndProjectId(String name, String projectId, Pageable pageable);
}
Exception:
2019-02-08 23:25:21.199 INFO 12556 --- [nio-8080-exec-1] c.a.m.A.controller.ProjectController : Inside searchEpicsByProjectIdAndSearchParam() API in EpicServiceImpl
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter with that position [1] did not exist; nested exception is java.lang.IllegalArgumentException: Parameter with that position [1] did not exist
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:525)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:209)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
Caused by: java.lang.IllegalArgumentException: Parameter with that position [1] did not exist
at org.hibernate.jpa.spi.BaseQueryImpl.findParameterRegistration(BaseQueryImpl.java:502)
at org.hibernate.jpa.spi.BaseQueryImpl.setParameter(BaseQueryImpl.java:692)
at org.hibernate.jpa.spi.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:181)
at org.hibernate.jpa.spi.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:32)
at org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:141)
at org.springframework.data.jpa.repository.query.StringQueryParameterBinder.bind(StringQueryParameterBinder.java:61)
at org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:101)
at org.springframework.data.jpa.repository.query.SpelExpressionStringQueryParameterBinder.bind(SpelExpressionStringQueryParameterBinder.java:76)
at org.springframework.data.jpa.repository.query.ParameterBinder.bindAndPrepare(ParameterBinder.java:161)
at org.springframework.data.jpa.repository.query.ParameterBinder.bindAndPrepare(ParameterBinder.java:152)
at org.springframework.data.jpa.repository.query.AbstractStringBasedJpaQuery.doCreateQuery(AbstractStringBasedJpaQuery.java:81)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:202)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$PagedExecution.doExecute(JpaQueryExecution.java:188)
Skip Single Quotations "'" around params i.e. ?1 and ?2. Working query will be like:
"select i.* from issue i where ("
+ "upper(i.name) like upper(%?1%))"
+ "and upper(i.project_id) = upper(%?2%)"
+ "ORDER BY i.name DESC \n-- #pageable\n",
countQuery =
"select count(i.*) from issue i where ("
+ "upper(i.name) like upper(%?1%))"
+ "and upper(i.project_id) = upper(%?2%)"

How come my Test fails in Docker Maven container 3.5.4-jdk8 when it passes using maven on command line

I have the following test which passes in IDE, and when run as Junit and even from the command line using mvn clean verify.
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
#RunWith(SpringRunner.class)
#WebFluxTest(controllers = AddNewEntryController.class)
#Import({ThymeleafAutoConfiguration.class})
public class AddNewEntryControllerTest {
#Autowired
WebTestClient webTestClient;
#MockBean
TimeKeepingEntryService service;
#Captor
private ArgumentCaptor<Flux<TimeKeepingEntry>> captor;
#Autowired
AddNewEntryController controller;
LocalDateTime now = LocalDateTime.now();
String month = now.getMonth().getDisplayName(TextStyle.FULL, Locale.ENGLISH);
TimeKeepingEntry entry1 = new TimeKeepingEntry(month,
now.getDayOfMonth(), now.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH), now.toLocalTime(),
LocalTime.parse("00:30", DateTimeFormatter.ofPattern("HH:mm")),
now.toLocalTime().plusHours(7), "7.5", false );
#Test
public void addNewEntryPage() {
EntityExchangeResult<String> result = webTestClient
.get().uri("/add-new-entry")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).returnResult();
assertThat(result.getResponseBody())
.contains("<title>Add New Time Entry</title>")
.contains("<input type=\"text\" class=\"form-control\" readonly=\"readonly\" id=\"month\" name=\"month\" value=\"" + month + "\">")
.contains("<input data-date-format=\"dd\" id=\"datepicker\" name=\"dateOfMonth\" value=\"0\">")
.contains("<input type=\"text\" class=\"form-control\" id=\"day\" name=\"day\" value=\"" + now.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH) + "\">");
}
#Test
public void addNewEntrySubmit() {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("month", month);
formData.add("dateOfMonth", Integer.toString(21));
formData.add("day", "Tuesday");
formData.add("startTime", "09:00");
formData.add("endTime", "17:00");
formData.add("breakLength", "00:30");
formData.add("onsite", Boolean.toString(false));
given(service.addTimeKeepingEntry(any())).willReturn(Mono.empty());
webTestClient.post().uri("/add-new-entry").accept(MediaType.TEXT_HTML).contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData(formData)).exchange().expectStatus().isSeeOther().expectHeader().valueEquals(HttpHeaders.LOCATION, "/");
verify(service).addTimeKeepingEntry(captor.capture());
TimeKeepingEntry timeKeepingEntry = captor.getValue().blockFirst();
assertThat(timeKeepingEntry.getMonth()).isEqualTo(month);
}
}
However when I push the code to Gitlab.com and the CI takes over and uses the maven docker container 3.5.4-jdk8 it fails with the following error.
Field error in object 'timeKeepingEntry' on field 'startTime': rejected `value [09:00]; codes typeMismatch.timeKeepingEntry.startTime,typeMismatch.startTime,typeMismatch.java.time.LocalTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [timeKeepingEntry.startTime,startTime]; arguments []; default message [startTime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalTime' for property 'startTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [#javax.validation.constraints.NotNull java.time.LocalTime] for value '09:00'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [09:00]]]`

Postgres Parameter Query for SimpleJdbcTemplate

I am trying to execute a parameter query for a Postgre database using Springs SimpleJdbcTemplate. My class that calls the query looks like this:
public class GeoCodeServiceImpl extends SimpleJdbcDaoSupport implements GeoCodeServiceInterface {
public static final String SELECT_STATEMENT = "SELECT ste_code, ste_code_type, name, fips_code " +
"FROM \"steGeo\" " +
"WHERE st_contains( the_geom, ST_GeomFromText('POINT(:lon :lat)',4269))";
public List<GeoCode> getGeoResults(Double lon, Double lat) throws DataAccessException {
MapSqlParameterSource mappedParms = new MapSqlParameterSource("lon", lon.toString());
mappedParms.addValue("lat", lat.toString());
SqlParameterSource namedParms = mappedParms;
List<GeoCode> resultList = getSimpleJdbcTemplate().query(SELECT_STATEMENT, new GeoCodeRowMapper(), namedParms);
if (resultList == null || resultList.size() == 0) {
logger.warn("No record found in GeoCode lookup.");
}
return resultList;
}
protected static final class GeoCodeRowMapper implements RowMapper<GeoCode> {
public GeoCode mapRow(ResultSet rs, int i) throws SQLException {
GeoCode gc = new GeoCode();
gc.setCode(rs.getString(1));
gc.setType(rs.getString(2));
gc.setFips(rs.getString(3));
gc.setName(rs.getString(4));
return gc;
}
}
}
I am testing the query with this class:
public class GeoCodeServiceTest {
public static void main(String[] args) {
Double lat = 40.77599;
Double lon = -83.82322;
String[] cntxs = {"project-datasource-test.xml","locationService-context.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(cntxs);
GeoCodeServiceImpl impl = ctx.getBean("geoCodeService", GeoCodeServiceImpl.class);
List<GeoCode> geoCodes = impl.getGeoResults(lon, lat);
System.out.println(geoCodes);
}
}
I keep getting the following error:
2011-03-07 08:16:29,227 [main] DEBUG org.springframework.jdbc.support.SQLErrorCodesFactory - SQL error codes for 'PostgreSQL' found
2011-03-07 08:16:29,227 [main] DEBUG org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator - Unable to translate SQLException with SQL state 'XX000', error code '0, will now try the fallback translator
2011-03-07 08:16:29,227 [main] DEBUG org.springframework.jdbc.support.SQLStateSQLExceptionTranslator - Extracted SQL state class 'XX' from value 'XX000'
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [SELECT ste_code, ste_code_type, name, fips_code FROM "steGeo" WHERE st_contains( the_geom, ST_GeomFromText('POINT(:lon :lat)',4269))]; SQL state [XX000]; error code [0]; ERROR: parse error - invalid geometry
Hint: "POINT(" <-- parse error at position 6 within geometry; nested exception is org.postgresql.util.PSQLException: ERROR: parse error - invalid geometry
Hint: "POINT(" <-- parse error at position 6 within geometry
It looks like my parameters are not populated.
I haven't used Postgre before so any help would be much appreciated.
Thanks
Parameters are not handled inside quoted strings, so I guess you need to pass the whole string as a single parameter:
public static final String SELECT_STATEMENT =
"SELECT ste_code, ste_code_type, name, fips_code " +
"FROM \"steGeo\" " +
"WHERE st_contains( the_geom, ST_GeomFromText(:pt, 4269))";
...
MapSqlParameterSource mappedParms = new MapSqlParameterSource("pt",
"POINT(" + lon.toString() + " " + lat.toString() + ")");

Spring new object Binding Exception: Cannot convert String to long (primitive type)

OS: Windows vista, Framework: Spring (latest), JQuery (latest), Hibernate (latest).
I have a domain class with primary key as long id.
public class domain{
private long id;
....
}
My Controller definition:
#RequestMapping("/domainJqgridData/save")
public #ResponseBody String saveJqgridData(DomainClass domainclass) throws Exception {
return "Saved successfully!";
}
When the JSP form is submitted to add a new DomainClass record, the Spring controller tries to automatically bind the request parameters to domain class. It throws a BindException as follows:
Request processing failed; nested exception is org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'domain' on field 'id': rejected value [_empty]; codes [typeMismatch.domainclass.id,typeMismatch.id,typeMismatch.long,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [domainclass.id,id]; arguments []; default message [id]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'long' for property 'id'; nested exception is org.springframework.core.convert.ConversionFailedException: Unable to convert value "_empty" from type 'java.lang.String' to type 'long'; nested exception is java.lang.NumberFormatException: For input string: "_empty"]
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:656)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
As I am adding a new DomainClass record, the id field is passed as null by the JSP form. Spring converts the null id to empty string value for binding purpose and throws the error. I browsed the net and found that I can register custom editors for such purpose. I changed the DomainClass primitive type definition long id, to Long id and tried to bind a custom editor as follows.
Controller class:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Long.class, new CustomPrimitiveFormat(Long.class, true));
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
My custom primitive editor class is as follows:
public class CustomPrimitiveFormat extends CustomNumberEditor{
public CustomPrimitiveFormat(Class numberClass, boolean allowEmpty)
throws IllegalArgumentException {
super(numberClass, allowEmpty);
// TODO Auto-generated constructor stub
}
public void setValue(Object value){
System.out.println("Entered CustomPrimitiveFormat setValue");
if (value == null) {
super.setValue(null);
return;
}
if (value.getClass().equals(String.class)){
if (StringUtils.isEmpty((String)value)){
super.setValue(null);
}
}
}
public void setAsText(Object value){
System.out.println("Entered CustomPrimitiveFormat setAsText");
if (value == null) {
super.setValue(null);
return;
}
if (value.getClass().equals(String.class)){
if (StringUtils.isEmpty((String)value)){
super.setValue(null);
}
}
}
}
I still receive the BindingException. Could not find any link that would guide me through how to overcome Spring BindException when adding a new Domain class record. I would like my primary key to remain primitive type, instead of using the Number object type.
Thanks in advance for your help.
As you can see in the error message, jqGrid uses _empty as an id of the new record (also see here), so you need to change your PropertyEditor to convert _empty to null.

Resources