spring data JPA & spring data elasticsearch; No property index found for type? - spring

I'm unsure why this is happening! I've got a class that is used by spring data elasticsearch and spring data jpa, but when I try run my application I get an error.
Error creating bean with name 'articleSearch':
Invocation of init method failed; nested exception is
org.springframework.data.mapping.PropertyReferenceException:
No property index found for type Article!
Caused by: org.springframework.data.mapping.PropertyReferenceException:
No property index found for type Article!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) ~[spring-data-commons-1.11.4.RELEASE.jar:na]
I've got the following application class:
#SpringBootApplication
#EnableAsync
#ComponentScan(basePackages = {"com.article.models", "com.user"})
public class ArticleApplication {
And the following elasticsearch config:
#Configuration
#EnableElasticsearchRepositories(basePackages = "com.article.search")
public class ElasticSearchConfiguration {
#Resource
private Environment environment;
#Bean
public Client client() {
TransportClient client = new TransportClient();
TransportAddress address = new InetSocketTransportAddress(environment.getProperty("elasticsearch.host"), Integer.parseInt(environment.getProperty("elasticsearch.port")));
client.addTransportAddress(address);
return client;
}
#Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchTemplate(client());
}
}
This is how I've setup my model class:
#Entity
#Table(name="article")
#Document(indexName="article", type="articles")
public class Article implements Serializable {
I've then got a package search that extends the elasticsearchrepository, like so:
public interface ArticleSearch extends ElasticsearchRepository<Article, String> {
I'm trying to autowire the articlesearch class inside another service which is causing the error to occur:
#Autowired
ArticleSearch articleSearch;
What am I missing here?! I guess it's a bit more complex when trying to use data-jpa + data-elasticsearch.

I found out why this was happening. I'm not sure why, but spring didn't seem to be picking up my ElasticSearchConfiguration configuration class!
So I simply moved all the contents from that and dumped it in my main application class (where all my other config is).
I also removed component scan & added the enablejparepository + enableelasticsearchrepository annotations to my main class. Here is what it looks like now:
#SpringBootApplication
#EnableAsync
#EnableElasticsearchRepositories(basePackages = "com.article.search")
#EnableJpaRepositories(basePackages = {"com.article.dao", "com.user.dao"})
public class ArticleApplication {

Related

Spring Context doesn't seem to recognize a Bean when creating it with stereotype annotations. Throws NoSuchBeanDefinitionException

I'm following a book to learn some modules of the Spring ecosystem. Currently trying to create beans using stereotype annotations.
I've written a simple Java class and marked it as a component:
package main.parrot;
#Component
public class Parrot {
private String name;
// getters and setters //
}
I then created a #Configuration class which scans for the Parrot component:
package main;
//imports
#Configuration
#ComponentScan(basePackages = "parrot")
public class ProjectConfig{}
In my main method I am creating a spring context using the configuration above, and I'm trying to access the bean Parrot:
package main;
//imports//
public class Main{
public static void main(String...args){
var context = new AnnotationConfigApplicationContext(ProjectConfig.class);
var p = context.getBean(Parrot.class);
}
}
The line of code in which I attempt to get the Parrot bean throws the following exception:
NoSuchBeanDefinitionException: No qualifying bean of type 'main.parrot.Parrot' available
I just don't understand why this configuration wouldn't find the Parrot bean. If someone could help me clarify the issue I would be extremely grateful.
Thank you in advance
You need to change the basePackages to include the complete package name:
package main;
//imports
#Configuration
#ComponentScan(basePackages = "main.parrot")
public class ProjectConfig{}

#ConfigurationProperites not binding to property source after upgrading to Spring Cloud Hoxton.SR7

I have a #ConfigurationProperties class that is no longer binding to a YML property source that gets resolved via Spring Cloud Config after upgrading to Hoxton.SR7. This code works fine using Hoxton.SR4 with the latest Spring Boot 2.2.9.RELEASE. Now, my properties are not bound and I'm receiving NPEs when I try to reference them. Following is a snapshot of my code:
#Configuration
public class MyConfiguration {
#Bean
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
In src/main/resources/META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.acme.MyConfiguration
Any ideas why my #ConfigurationProperties class doesn't bind after upgrading Spring Cloud to Hoxton.SR7?
You're mixing two ways of binding properties: class and method.
Using a method and #Bean annotation:
#Configuration
public class MyConfiguration {
#Bean
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
This will create MyPropertiesBean and store it inside the application context for you to inject.
Class level bean declaration also creates a bean for you:
#Configuration
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
This will also store a bean.
Although, you should be getting a runtime error when you try to inject MyPropertiesBean as now in your case there's two beans of the same type and Spring cannot resolve with only the type.

Why #Configuration class required for #ConditionalOnEnabledEndpoint annotation?

I'm using Spring Boot 2.1.6 version. Can't we use the #ConditionalOnEnabledEndpoint annotation with #Component? I get
Caused by: java.lang.IllegalStateException: OnEnabledEndpointCondition must be be used on #Bean methods when the endpoint is not specified
I tried a class like below
#Component
#Endpoint(id="customendpoint")
#ConditionalOnEnabledEndpoint
class MyCustomEndpoint {
#ReadOperation
public String method1() { ....... }
}
#ConditionalOnEnabledEndpoint is working when I create a configuration class and #Bean method.
Why Configuration class is required ?
Is there any other way to stop the component exposing the actuator endpoint with out configuration class.
You have to set the endpoint attribute, see ConditionalOnEnabledEndpoint#endpoint
public abstract Class<?> endpoint
The endpoint type that should be checked. Inferred when the return type of the #Bean method is either an Endpoint or an EndpointExtension.
Returns:
the endpoint type to check
Since:
2.0.6
Default:
java.lang.Void.class
Your modified code:
#Component
#Endpoint(id="customendpoint")
#ConditionalOnEnabledEndpoint(endpoint = MyCustomEndpoint.class)
class MyCustomEndpoint {
#ReadOperation
public String method1() { ....... }
}

Ignore JNDI-Resource injection (#Resource) in Spring

I am currently experimenting with Spring Boot and I'm trying to include a library class which is currently used in a Java EE context.
Said class has a parent class which has a #Resource injection with a JNDI lookup name.
In a reduced example, the involved classes look like this:
Configuration.java
#Configuration
public class Facades {
#Bean
public Connection connection() {
return new Connection();
}
#Bean
public Facade facade(Connection connection) {
return new Facade(connection);
}
}
Facade + ParentFacade
public class ParentFacade {
#Resource(lookup = "eis/Connection") // <-- the problem
protected Connection connection;
}
public class Facade extends ParentFacade {
public Facade(Connection connection) {
this.connection = connection;
}
}
When I run the application, following error appears:
Invalid bean definition with name 'eis/Connection' defined in JNDI
environment: JNDI lookup failed; nested exception is
javax.naming.NoInitialContextException: Need to specify class name in
environment or system property, or as an applet parameter, or in an
application resource file: java.naming.factory.initial
Obviously, I don't need the #Resource injection since I can inject the connection by constructor.
However, Spring always attempts to inject a bean with the JNDI name dynamically.
I have tried to exclude the class from IoC inclusion with following annotations, but it made no difference:
#Configuration
#ComponentScan(
basePackages = "the.package",
excludeFilters = #ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = { Facade.class, ParentFacade.class }
)
)
My question now is:
Can I either
make Spring ignore the #Resource annotation in the problematic class OR
inject a #Bean with the required JNDI-name (eis/Connection)?
Thanks in advance!
P.S.:
changing the library class which contains the #Resource annotation is not an option
I think, you need #Resource(name = "connection")

Cannot resolve bean in SpEL for Spring Data MongoDB collection name

I am trying to customize the collection name where an entity class is saved into and indexed, using Spring Data MongoDB and Spring Batch. The class is declared as follows:
#Document
#CompoundIndex(name = "unique_source", def = "{'fid': 1, 'sid': 1}", unique = true, background = true)
public class VariantSource {
...
}
And the item writer:
public class VariantSourceMongoWriter extends MongoItemWriter<VariantSource> {
public VariantSourceEntityMongoWriter(MongoOperations mongoOperations, String collectionName) {
setTemplate(mongoOperations);
setCollection(collectionName);
}
}
Saving works fine: the objects are written into the collection provided as argument. The problem is that the indexes are created in the default collection, named after the class name (variantSource).
After reading this and this, I created the following:
public class MongoCollections {
public String getCollectionFilesName() {
return "my_custom_collection_name"; // TODO Dynamic value
}
}
#Configuration
public class MongoCollectionsConfiguration {
#Bean
public MongoCollections mongoCollections() {
return new MongoCollections();
}
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {MongoCollectionsConfiguration.class})
public class VariantSourceMongoWriterTest {
#Autowired
private MongoCollections mongoCollections;
}
I have checked the instance is correctly autowired into the unit tests, but I can't make it work with SpEL.
After changing the #Document annotation to look like this:
#Document(collection = "#{#mongoCollections.getCollectionFilesName()}")
the following exception is thrown:
org.springframework.expression.spel.SpelEvaluationException: EL1057E:(pos 1): No bean resolver registered in the context to resolve access to bean 'mongoCollections'
And if I use this:
#Document(collection = "#{mongoCollections.getCollectionFilesName()}")
the exception is this one:
org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Property or field 'mongoCollections' cannot be found on null
Finally, the following creates a collection with the name as specified, symbols included:
#Document(collection = "#mongoCollections.getCollectionFilesName()")
As pointed by this answer, to fix the injection:
#Document(collection = "#{mongoCollections.getCollectionFilesName()}")
SpelEvaluationException: EL1007E:(pos 0): Property or field 'mongoCollections' cannot be found on null
(or a direct method bean: #Document(collection = "#{getCollectionFilesName}")), try setting the ApplicationContext into the MongoMappingContext (which is used to instantiate the MongoConverter, and later the MongoTemplate):
#Bean
public MongoMappingContext MongoMappingContext() {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setApplicationContext(applicationContext);
return mappingContext;
}
Make sure that your bean mongoCollections is registered in the application context,
and also correct the SpEL expression as below.
#Document(collection = "#{#mongoCollections.getCollectionFilesName()}")
I was able to get my #Document tag to access a bean by simply changing my MongoTemplate configuration file.
Previously, I had it set up like this:
#Configuration
public class MongoTemplateConfiguration {
...
#Bean
public MongoTemplate mongoTemplate() {
...
return new MongoTemplate(...);
}
}
Changing it to follow this (3.2 Java Configuration) format was all I needed in order to remove the "bean resolver" error:
#Configuration
public class MongoTemplateConfiguration extends AbstractMongoClientConfiguration {
...
#Override
#Bean
public com.mongodb.client.MongoClient mongoClient() {
MongoClientSettings settings = ...;
return MongoClients.create(settings);
}
}

Resources