IntelliJ + Spring: how to enable table names checking in HQL queries? - spring

I'm using Spring Boot 1.4.2 and both Hibernate and JPA in my project. I use IntelliJ Community 2016.2.4, same as my colleague. The difference is that when he types something in HQL (i.e. #Query("SELECT id FROM usesrs)) it automatically checks the table names against the real DB structure - there is no "usesrs" table, but there is a "user" table. So his project doesn't compile unless he corrects it - what a wonderful feature! Sometimes it takes me a lot of time to spot such bugs...
Can you tell me how can I enable this in IntelliJ? What I tried:
1) When I go to Preferences / Editor / Language injections / "+" sign / Java Parameter I don't see SQL on the list, not speaking about HQL (but JQL is there which is crazy...). Anyway looks like I want to enable something deeper than just plain syntax check, it has to check against the database structure.
2) When I go to File / Project structure / Facets / "+" sign I don't see JPA there, just some Android options and Java-Gradle.
Any suggestions here?

Unfortunate JPA/Hibernate features are supported in the Ultimate version.
IDEA has the Language Injections which can inject a language (such as SQL, RegExp, XML, HTML, CSS, etc.) into a string literal in your code and, as a result, get comprehensive coding assistance when editing that literal.
You can get a help here and a tip here to Using language injections in SQL

In the Database view is your datasource setup?
If it's not already visible go to view -> Tool Windows -> Database
There you should see a data source for your connection.
If it is not there you'll need to set it up using + -> "Data Source" then select the DB that your using and set up your connection.
Once this is done OR if the DB Connection is already present you'll want to synchronize the datasource using the "Refresh" looking icon in the Database view.
Then click on more schemas and pick the schema your using and hit Synchronize on that as well. Intellij should now know about the DB and your table structures.
Hopefully it can then check your queries automatically unless there is something else amiss.

Three conclusions on this topic:
1) As #Liping Huang pointed out, the live checks (and I imagine mistakes highligting) is only in Ultimate edition
2) I investigated the issue more deeply and looks like I actually have some basic support for this, but I just omitted the error message hidden lower in the stack. In the Community I have to try to run the app, so no live highlighting. Then, if there is an error in the table name, the message will be in the stack trace.
Here is the example, notice the "Usesrs is not mapped" message:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'protectedController': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userRepositoryImpl': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract void com.ekinnolab.database.repository.user.userRepository.setAsDeletedById(java.lang.Long)!
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:592) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
(…)
// cutting out 150 about lines
(...)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:240) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1894) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:291) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
... 69 common frames omitted
HERE ==> Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Usesrs is not mapped
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:171) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:91) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.ast.tree.FromClause.addFromElement(FromClause.java:76) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromElement(HqlSqlWalker.java:321) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3687) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3576) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:716) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.java:373) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:265) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:262) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:190) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
... 77 common frames omitted
3) BTW, for pure SQL there are some interesting plugins out there. Just go to IntelliJ IDEA / Preferences / Plugins / Browse repositories. "SQL Query Plugin" is one of those looking promising.

Related

Mocking a Supplier<>-Bean

I would like to mock a Bean (using mockito) that is defined like so
#Bean("idGenerator")
public Supplier<UUID> idGenerator() {
return () -> UUID.randomUUID();
}
In a SpringBootTest-class I get an error using #MockBean indicating, that that Bean cannot be mocked (due to some limitations in the JVM? - sorry, I don't have the stacktrace at hand right now).
I came up with a workaround that does not use Mocks but an additional field in a #TestConfiguration so that the return-value of the supplier can be specified externally.
Since I don't really like that workaround (and my colleagues won't either), I hope there is a proved pattern or the realization I am doing that mocking wrong.
Edit
Here is the stacktrace I am getting. As Markus pointed out - the standard unit-tests work - it seems to be a shortcoming of cucumber-java:
Before All/After All failed
io.cucumber.core.exception.CompositeCucumberException: There were 15 exceptions. The details are in the stacktrace below.
at io.cucumber.core.runtime.RethrowingThrowableCollector.getThrowable(RethrowingThrowableCollector.java:57)
at io.cucumber.core.runtime.CucumberExecutionContext.getThrowable(CucumberExecutionContext.java:102)
at io.cucumber.core.runtime.CucumberExecutionContext.finishTestRun(CucumberExecutionContext.java:97)
at io.cucumber.core.runtime.Runtime.execute(Runtime.java:96)
at io.cucumber.core.runtime.Runtime.run(Runtime.java:87)
at io.cucumber.core.cli.Main.run(Main.java:87)
at io.cucumber.core.cli.Main.main(Main.java:30)
Suppressed: java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
at io.cucumber.spring.TestContextAdaptor.<init>(TestContextAdaptor.java:32)
at io.cucumber.spring.SpringFactory.start(SpringFactory.java:120)
at io.cucumber.core.runner.Runner.buildBackendWorlds(Runner.java:134)
[...]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name [...]: Unsatisfied dependency expressed through constructor parameter 5: Initialization of bean failed;
nested exception is org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class BackendApplicationConfiguration$$Lambda$1713/0x00000008018fd980
Mockito cannot mock/spy because :
- VM does not support modification of given type
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
You can just define it like follows:
#MockBean(name = "idGenerator")
private Supplier<UUID> mockedSupplier;
there is no issue that prevents this from mocking. Would be good to include your stacktrace, as the issue is probably somewhere else.

No [ManagedType] was found for the key class [nz.cri.gns.mapservice.userdomain.DataUser]

I have two data sources. The moment I add ANY repository to the second datasource, this error comes up for whatever entity the repository used.
Using spring config instead of persistance, and EclipseLink JPA. The strange thing is that is has nearly identical to a working project that was used as template. Different data sources and obviously different tree scanned, but otherwise the config seems setup exactly the same. What is the equivalent spring data config equivalent to exclude-unlisted-classes. I will happily put up code but can anyone give me hint of where I should start looking?
stackdump looks like:
Caused by: java.lang.IllegalArgumentException: No [ManagedType] was found for the key class [nz.cri.gns.mapservice.userdomain.DataUser] in the Metamodel - please verify that the [Managed] class was referenced in persistence.xml using a specific nz.cri.gns.mapservice.userdomain.DataUser property or a global false element.
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.entityEmbeddableManagedTypeNotFound(MetamodelImpl.java:177)
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:519)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.(JpaMetamodelEntityInformation.java:68)
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:67)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:152)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:99)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:81)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:185)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:251)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:237)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
Duh! Make sure everything in the SetPackagesToScan is spelled correctly! No errors result from a typo, but classes dont go into the metamodel either.

Using spring-data-mongodb and spring-data-neo4j together

How can I use spring-data-mongodb and spring-data-neo4j in the same spring-boot application?
I can easily use one or the other following the "getting started" guides, but as soon as I try to add Neo4J to a MongoDB application then I get runtime errors such as:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'application': Unsatisfied dependency expressed through field 'repository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bookRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property findAll found for type MongoBook!
I've setup a minimal example at https://github.com/afaulconbridge/myspring-mongo-neo
You can try this project which uses JPA and Neo4J together. The structure should technically work with Mongo as well. Be aware though that Mongo doesn't support the concept of transactions so you may not have to define an explicit transaction manager for each Spring Data project.
As #manish pointed out, you need to make Spring Data MongoDB and Spring Data Neo4J scan separate packages. i.e.
#EnableMongoRepositories(basePackageClasses=MongoBook.class)
#EnableNeo4jRepositories(basePackageClasses=NeoAuthor.class)
I've updated the example project at https://github.com/afaulconbridge/myspring-mongo-neo with a solution.
You should be able to use excludeFilters and includeFilters parameters respectively even in the same package (in most cases includeFilters is enough)
#EnableMongoRepositories(basePackageClasses=MongoBook.class,
includeFilters ={#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = {MongoRepository.class}))
#EnableNeo4jRepositories(basePackageClasses=NeoAuthor.class,
includeFilters ={#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = {NeoRepository.class}))
from includeFilters() description
Specifies which types are eligible for component scanning. Further
narrows the set of candidate components from everything in {#basePackages()} to everything in the base packages that matches the given filter or filters.

Cannot convert value of type [org.hibernate.impl.SessionFactoryImpl] to required type [com.liferay.portal.kernel.dao.orm.SessionFactory]

I got this exception!!!
Caused by: java.lang.IllegalStateException: Cannot convert value of type [org.hibernate.impl.SessionFactoryImpl] to required type [com.liferay.portal.kernel.dao.orm.SessionFactory] for property 'sessionFactory': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:289)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:154)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:452)
... 41 more
Do you have any solution?
One of the beans that you pass sessionFactory to them require the Liferay one instead of the Hibernate one.
There are 2 possible mistakes:
You made a mistake in wiring - fix that by passing Lifray's SessionFactory (create one if you don't have one already)
The mistake is in Java class imports - fix the imports

MyBatis/Spring - 2 Datasources MyBatisSystemException - Ambigous mapped statements

I have configured two datasources in my Spring/MyBatis application. I don't get any error while startup (its reading the Mapper XML and interface). But when invoking the method, its throwing the following exception:
MyBatisSystemException: SqlSession operation; nested exception is java.lang.IllegalArgumentException: selectByPrimaryKey is ambiguous in Mapped Statements collection (try using the full name including the namespace, or rename one of the entries)
It doesn't quite clearly say the cause for ambiguity.

Resources