Hibernate Search 6 #ProjectionConstructor not working - spring-boot

I am experimenting the projection features of Hibernatesearch 6.2.0.Alpha1 before integrating our existing app.
I have created a spring-boot project with JHIPSTER sample project. And added the Hibernate-search dependencies and configurations in both POM.XML and application*.yml. Using JHipster because it helps me with the boilerplate code and fake data.
Have configured pom.xml with both -parameters and jandex. Application runs successfully and loads the data into the database. And i am able to mass Index with the utility we wrote as per the documents.
However when try to search the data with projections we are recieving the error Exception in searchWithProjection() with cause = 'NULL' and exception = 'HSEARCH700112: Invalid object class for projection: com.sample.shop.service.projections.dto.Address. Make sure that this class is mapped correctly, either through annotations (#ProjectionConstructor) or programmatic mapping. If it is, make sure the class is included in a Jandex index made available to Hibernate Search.'. The same query/logic works perfectly fine if we search without projections.
Ex. if you view the files AddressResource.java & AddressService.java in the above linked repository; you can find 2 implementations for projections and no-projections respectively. while the one without projections works perfectly fine the one with projects is throwing the error.
I feel it might be some configuration issue, however not able to figure-out myself. Appreciate your help on configuration / code approach.
Please be informed that I have gone through the follwoing tickets already:
Hibernate Search 6 combine projections not working
Single return type in Hibernate Search

Thanks for your reproducer. It's a bug: https://hibernate.atlassian.net/browse/HSEARCH-4724
I suggested a workaround here: https://github.com/anothergoodguy/spring-data-hibernate-search/pull/1
In short:
Add this class to your application:
package com.sample.shop.config;
import java.net.URISyntaxException;
import java.nio.file.Path;
import org.hibernate.search.mapper.orm.mapping.HibernateOrmMappingConfigurationContext;
import org.hibernate.search.mapper.orm.mapping.HibernateOrmSearchMappingConfigurer;
import org.hibernate.search.util.common.jar.impl.JandexUtils;
import org.springframework.stereotype.Component;
#Component("searchMappingConfigurer")
public class HibernateSearchMappingConfigurer implements HibernateOrmSearchMappingConfigurer {
#Override
public void configure(HibernateOrmMappingConfigurationContext context) {
// Workaround for https://hibernate.atlassian.net/browse/HSEARCH-4724
// => Hibernate Search doesn't seem to find the Jandex index in the fat JAR.
try {
var classesUri = getClass().getProtectionDomain().getCodeSource().getLocation().toURI();
var ssp = classesUri.getSchemeSpecificPart();
var jarpath = Path.of(ssp.substring(ssp.indexOf(":") + 1, ssp.indexOf("!")));
context.annotationMapping().add(JandexUtils.readIndex(jarpath).get());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
Reference it in your configuration:
jpa:
properties:
hibernate.search.mapping.configurer: bean:searchMappingConfigurer
And voilĂ .
Note it's just a workaround and relies on internal code that may break at any time. But, well, at least it works, so it's fine until the bug gets fixed.

Here are the instructions to run the application:
All the needed ecosystem like Elasticsearch, kibana and MySql are added in eco.yml file under src/main/docker/eco.yml
Please use the following command to bring the ecosystem up docker-compose -f src/main/docker/eco.yml up -d && docker-compose -f src/main/docker/eco.yml logs -f
On a different termina tab/window, Build the application with the following command ./mvnw clean package -Pprod,api-docs -Dskip.Tests -Dmaven.test.skip=true
to run the application run the following command java -jar target/shop-app-0.0.1-SNAPSHOT.jar
Once the application is started, it will show that it's listneing on [http://localhost:8080]. Please open the same url on the browser and login with the default administrator User:admin and Password:admin.
Then please navigate to swagger from Administrator menu and API menu-item.
We need to Mass-Index the fake data that's is already loaded from swagger from same swagger window: by executing the post on /api/mass/index on the resource Elastic Search Mass Indexing API
Then please go to the address-resource :
Request without Projections access /api/_search/addresses with
query string aa - This will result in success
Request with Projections access /_search/addresses/projection with same query string aa - This will result in failure

Related

Spring Boot code, workflow is -> upload file - then tamper with file - download the file

I am doing the following tutorial at spring.io (https://spring.io/guides/gs/spring-boot/) and this is my first spring-boot application, I am a java-developer. I am using the Maven-approach and deploying it as a stand-alone jar (not relevant to the use-cases really).
The question about the code has to do with structuring and boils down to the question "where should I put in my 'business-logic'?". The logic that I would like to apply concerns the following 2 use-cases.
I want to transform 2 columns in the uploaded csv-file (or excel-file) and let the user download the 'transformed'-file.
If the user uploads an image file, I want to check if there are any EXIF-Tags (such as coordinates ++ ) in the image - and if there is, I would like to store that information in a database.
Or should I take a broader look at Spring MVC or similar technologies when it comes to my use-cases ?
best, Ingo
Right now I am running Ubuntu 18.04 and using java 1.8, maven 3.0.5 and Netbeans 8.2.
To answer your question:
"where should I put in my 'business-logic'?"
You basically want your Controller to handle your requests only and let another class handle the logic, which is a Service in Spring terms.
You would have a file MyService.java similar to this:
#Service
class MyService {
public MyData handleCSV(<your parameters>) {
return ...
}
}
In your Controller you can inject your service and simply use it:
#Controller
class MyController {
#Autowired
private MyService myService;
}
That's it. Anywhere in this controller, you can call the myService instance.

Gemfire CacheListenerAdapter implementation ClassNotFoundException: org.apache.geode.pdx.internal.PdxType

I'm getting the following error when I tried to implement CacheListenerAdapter from gemfire.
java.lang.ClassNotFoundException: org.apache.geode.pdx.internal.PdxType
I am using the following code for getting the cache values from gemfire.
import com.gemstone.gemfire.cache.Declarable;
import com.gemstone.gemfire.cache.EntryEvent;
import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
import com.gemstone.gemfire.pdx.internal.PdxInstanceImpl;
#Override
public void afterUpdate(EntryEvent<K, V> event) {
addToQueue((PdxInstanceImpl) event.getNewValue());
}
and I'm reading the price using the following code in addToQueue function
Double price = Double.parseDouble(instance.readField("Price").toString());
Please note that I copied this code from another project and I'm new to gemfire. I use the above code to plot data in a window.
The client needs to be running v8.2.2 or later. Code to translate the org.apache.geode package names to com.gemstone.gemfire was added in that release.
following error you can get because of gemfire server and client has diffrent jar version.
java.lang.ClassNotFoundException: org.apache.geode.pdx.internal.PdxType
at com.gemstone.gemfire.internal.ClassPathLoader.forName(ClassPathLoader.java:422) ~[gemfire-8.2.0.jar:na]
For debugging issue you need to check error logs
com.gemstone.gemfire.internal.ClassPathLoader.forName(ClassPathLoader.java:422) ~[gemfire-8.2.0.jar:na]
You can see "gemfire-8.2.0.jar" now check your server version and change client jar as per server .

REST Client Grails Groovy unable to resolve class RestClientBuilder

I have an empty project created using GGTS, my app runs fine, I can see the views and navigate through them fine.
I need con call a REST api and consume the data provided, I read and added the necessary plug in to the BuildConfig file under the dependencies and then under the plugins section, none of them seem to work.
compile ":rest-client-builder:2.0.0"
I've created a controller, I'm not sure where to add the import here, so I've tried:
package myapp
class UserController {
def index() {
import grails.plugins.rest.client.RestBuilder
String url = "https://foo.com/batch/$id"
def resp = new RestBuilder().get(url) { header 'Authorization', 'Basic base64EncodedUsername&Password' }
render resp
}
but I get the error: unable to resolve class....
The API is returning JSON data, what I;ve done so far is just to create a new Grails project, add controller, add view and then the dependency.
I've cleaned an built the project several times but the error remains.
Thanks for your help.
Import goes at the top
After the package line
And before the class line
Also, depending on your version of grails, you might want to move of ggts... Not sure it's supported any more...
I think that the problem is in your build.gradle dependency definition.
Insert the next line to your build.gradle file and I think that will be helpful:
compile "org.grails.plugins:rest-client-builder:2.1.1"
For more information follow the grails plugin documentation.
Please be aware that all the business logic should be placed in the service layer and not in the controller. It is a best practice to keep your controller lean as possible.
Another best practice is to define the following line:
String url = "https://foo.com/batch/$id"
in the beggining of the controller as static final String
static final String url = "https://foo.com/batch/"
and add the $id when needed in the code.
Here is how that should be called inside the method:
String url = "${url}/{$id}"

OSGi bundle config without managed service or factory

Neil Bartlett's article http://njbartlett.name/2010/07/19/factory-components-in-ds.html shows the way to set config for bundles without using managed service or managed factory.
Search for examples of actually setting the config for this method either point to felix file install or to examples using managed service.
In answer to the question OSGi Declarative Services vs. ManagedService for configuring service? Neil Bartlett states "Note that DS never actually creates a ManagedService or ManagedServiceFactory for your component. It works by listening to Config Admin with a ConfigurationListener. However the internal details are unimportant... simply create configs with PID/factoryPID matching the component.name and it "just works"
I think the technique involves placing a pid entry in the config dictionary but I have no idea how this would be used with config admin.
A guide or simple example of how to set the configuration using this method would be very helpful.
I know it is some time since the question was asked, but I ran into the same problem when trying to create a ManagedServiceFactory-like Component with Declarative Services. So I want to share my solution. Maybe others find it useful. My problem was like this:
I have defined a component (annotated with #Component). On each configuration I add using felix file-install, I want an instance of that component created with the given configuration and activated immediately.
First I tried messing with the properties factory and configurationPid of #Component, but all that is not needed and even returns wrong results (felix annotation processor in the maven plugin seems to have a bug when handling configurationPid).
The solution I came up with:
package com.example.my;
#Component(
name = MyExampleComponent.FACTORY_PID,
configurationPolicy = ConfigurationPolicy.REQUIRE,
property = {"abc=", "exampleProp="}
)
public class MyExampleComponent {
public static final String FACTORY_PID = "com.example.my.component";
#Activate
protected void activate(BundleContext context, Map<String,Object> map) {
// ...
}
}
Then I created a config file for felix file-install named com.example.my.component-test1.cfg:
abc = Hello World
exampleProp = 123
When deployed this automatically creates a folder structure in the configuration folder like com/example/my/component containing the files:
factory.config
contents:
factory.pid="com.example.my.component"
factory.pidList=[ \
"com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f", \
]
.
525ca4fb-2d43-46f3-b912-8765f639c46f.config
contents:
abc="Hello World"
exampleProp="123"
felix.fileinstall.filename="file:/..._.cfg"
service.factoryPid="com.example.my.component"
service.pid="com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f"
The 525ca4fb-2d43-46f3-b912-8765f639c46f seems to be some randomly generated ID (possibly UUID).

How to get Spring 3.1.1 works with App Engine datastore

Could everyone show me a tutorial on how to make Spring 3.1.1 running on Google App Engine, please?
I've followed severals tutorial and managed to get the dead simple HelloWorld example to work on App Engine. However, when I go futher, I stuck at the persistent process between Spring and Datastore. I looked at this thread Configuring JDO in Spring 3.1?, too, but it works on localhost but it doesn't work when I deploy to app engine due to the javax.naming.NamingException.
Therefore, I'm looking for a not-too-simple tutorial that covers basic aspects of a real life application such as the view, the model and the database.
Jappstart is a good place to see a working example of GAE that uses Spring and the Datastore (via JPA) and is also a good starting point for building a basic GAE/J app.
Having spent about a day trying to make this work, I thought I'd add some additional useful information here. First take a look at this project https://github.com/hleinone/spring-gae-jdo and this issue: http://code.google.com/p/googleappengine/issues/detail?id=1240 -- comment 24 is the useful one.
In case anyone wants to get this working with annotation-driven configuration, here's how I did it:
package com.domain.yourcode.configuration;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jdo.GAETransactionAwarePersistenceManagerFactoryProxy;
import org.springframework.orm.jdo.JdoTransactionManager;
//import org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy;
#Configuration
public class JDOConfiguration {
private static final PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("transactions-optional");
#Bean
public GAETransactionAwarePersistenceManagerFactoryProxy proxyPmf() {
GAETransactionAwarePersistenceManagerFactoryProxy proxy =
new GAETransactionAwarePersistenceManagerFactoryProxy();
proxy.setTargetPersistenceManagerFactory(pmf);
proxy.setAllowCreate(false);
return proxy;
}
#Bean
public JdoTransactionManager transactionManager() {
JdoTransactionManager mgr = new JdoTransactionManager();
mgr.setPersistenceManagerFactory(pmf);
return mgr;
}
}
You'll still want <tx:annotation-driven/> in your applicationContext.xml

Resources