how Spring boot explicitly not load a class if it's not a web project? - spring-boot

An independent common project A which supply common configuration, inside it there is a class
#RestController
public class CustomErrorController implements ErrorController {
#Autowired
private ErrorAttributes errorAttributes;
//...
}
Now there is another project B which depend on above project A, but this is not a web project only execute some business logic then exit. So in application.properties I have this configuration:
spring.main.web_environment=false
but when run project B, it failed because this exception:
No qualifying bean of type [org.springframework.boot.autoconfigure.web.ErrorAttributes] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
So how to solve this problem? Could exclude CustomErrorController in B's pom.xml or if it's not a web project could not load CustomErrorController?

spring.main.web_environment=false disable the embedded container even if it is present in your project. It does not perform black magic to prevent your classes to be instantiated.
If you are using component scan and you provide classes that require a web environment it will fail (as you just saw). Maybe you need to refactor your project in several modules and isolate the web part in a separate project?

exclude CustomErrorController class
#ComponentScan(basePackages = "com.foo",
excludeFilters = {#ComponentScan.Filter(value = ProjectAApplication.class,type = FilterType.ASSIGNABLE_TYPE),
#ComponentScan.Filter(value = CustomErrorController.class, type = FilterType.ASSIGNABLE_TYPE)})
#SpringBootApplication
public class ProjectBApplication implements CommandLineRunner {

Related

cannot Autowire a class from external jar in spring boot

Have a class A in a spring boot application. Have added a module in the pom, and i am able to import that class 'B' from that module in this class
but i am not able to autowire the same,
#EnableAutoConfiguration
class A
{
A(B b)
}
There are no compile time errors, but the application fails to start
Parameter 0 of method <> required a bean of type <> that could not be found
Tried annotating the main class with #ComponentScan({"package of class B"}) , no compile errors, but the application fails to start with same error, but with different classes.
thoughts ?
If you specify #ComponentScan with a specific package, Spring will only scan that package and subpackages for Spring beans. So if your different classes are in a different package structure, you have to add those packages as well in the annotation.

Spring Hibernate won't implement Repository Class from Interface

I have two separate projects. One project contains my Application logic and Controllers in org.patrick.application, and one separate project contains my Hibernate entities, Dao, and models in org.patrick.hibernate. My problem is that Spring will not instantiate a implementing class for my CrudRepository.
Here is my Application.java class annotations in my Application project:
package org.patrick.application;
#SpringBootApplication
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = { "org.patrick.hibernate" })
#EntityScan(basePackages = { "org.patrick.hibernate" })
#ComponentScan(basePackages = { "org.patrick.hibernate", "org.patrick.application" })
These annotations should scan my second Hibernate project for all of my Hibernate objects.
My Hibernate repository looks like this:
package org.patrick.hibernate;
#Repository
public interface PatrickDao extends CrudRepository<MyModel, Long>
This repository does not have a class implementation. I am expecting Spring to populate this implementation for me.
Now, inside of my application org.patrick.application, I am trying to use the Dao like so:
package org.patrick.application;
#Autowired
private PatrickDao patrickDao;
This is causing my Application project to fail to start because of the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean found for dependency [org.patrick.hibernate.PatrickDao]: expected at least 1 bean which qualifies as autowire candidate.
I know that the core problem is that Spring is not implementing this interface -
because if I provide my own PatrickDaoImpl in the org.patrick.hibernate package, then the Application project will start just fine. This confuses me because I have the proper annotations on my Application.java class, and yet the Repository cannot be implemented by Spring for some reason.
Is there anything further I need to do in order to get Spring to implement the class for my Repository interface? In previous testing, this behavior works if everything is under the same package.
I found the problem. For this particular Model, the definition looked as such:
package org.patrick.hibernate;
public class MyModel implements Serializable {}
This Model did not have the #Entity annotation. If this annotation is missing, then Spring will give no warnings as to why it cannot implement the repository interface. In my case, it simply threw the NoSuchBeanDefinitionException exception.
I updated my Model with the proper annotations:
package org.patrick.hibernate;
#Entity
public class MyModel implements Serializable {}

External Java Library issue with Autowiring and injecting bean

I have created a Spring Boot application managed by Maven.
I'm retrieving an company's library from our Maven repository.
In this library, we have a service interface, not being annotated with '#Service':
public interface MyService {
//...
}
This service has only one implementation :
public class DefaultMyService implements MyService {
//...
}
This library context is managed the old Spring way (in applicationContext.xml file).
I read that normally, Spring Boot is able to find the implementation if there's only one in the scope.
When I try to run "spring-boot:run" on my project, it will fail with the following error :
No qualifying bean of type 'com.pharmagest.saml.SAMLService'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I tried:
To add a #ComponentScan on the configuration class, including packages in error : #ComponentScan(basePackages={"com.mycompany.web", "com.mycompany.thelibrary.client.*", "com.mycompany.thelibrary.services.*"})
To add the bean definition in applicationContext.xml (if I add the interface it tells me it can define it, thus I heard that Spring can find the default implementation if there is only one ?)
To add library at "runtime" in projects options
To add the library as external resource not via maven
In all cases I just can maven build but can't run the project.
Do you have any advice to help me ? thanks!
Won't work as the DefaultMyService has no #Component (or #Service) annotation will not be detected.
Bean definition has to be a concrete instance so use DefaultMyService instead of the interface. Spring will not detect anything for you your understanding is wrong
and 4. Will not change anything only adding dependencies without proper 1. or 2. will do nothing.
Just add a #Bean to your configuration
#Bean
public DefaultMyService myService() {
return new DefaultMyService();
}
Or import the other libraries applicatiponContext.xml which is what you probably should do.
#ImportResource("classpath:/applicationContext.xml")
Add this next to the #SpringBootApplication.

Dynamic autowire in /src/groovy

I want to be able to include Services in my Groovy Classes in /src/groovy
I found a solution with :
myBean(MyBean) { bean ->
bean.autowire = 'byName'
}
But I dont want to make this entry in the resources.groovy for all Class, so is there a Solution to Autowire all classes in a specific folder?
I'm using grails 2.4.3
This seems to be similar to this question: Grails 2.x service injection in Groovy/src
What we use and is proposed there is to get the service via the application context:
import grails.util.Holders
...
def myService = Holders.grailsApplication.mainContext.getBean 'myService'
It's not completely auto-wired, but seems to be the best way to get services into src/groovy.
Edit: also works for Grails 3
You can make a class com.example.MyClass in src/groovy a Spring bean by adding the following to BuildConfig.groovy
grails.spring.bean.packages = ['com.example']
and annotating the class with #Component, e.g.
#Component
class MyClass {
#Value('${conf.apiVersion}')
String apiVersion
#Autowired
SomeService someService
}
As shown above, you can dependency-inject the class with the usual Spring annotations such as #Value and #Autowired. I find this a much more convenient way to register a Spring bean than modifying resources.groovy.

ComponentScan and Autowired not working for dependent Spring project?

I have two projects A and B. Both are built with Maven, and project A has a Maven dependency to project B. Both project have a class with #Configuration annotation where I define #Beans.
I have beans in project A, from both projects. If I use the #Autowired annotation in project A of a bean that is defined in same project, the autowiring works. However, if I use the #Autowired annotation in project A of a bean from project B, I will get an exception.
What does this mean? How can I autowire a bean in project A, that is defined in project B?
This is normally an issue with the base classpath on ComponentScan.
If you for example have the following base packages
com.myproject.a
and
com.myproject.b
in your project A and B respectively, and you're using SpringBoot with the main class
package com.myproject.a
#Configuration
#EnableAutoConfiguration
#ComponentScan
class MyApp {
// Some public static void main ...
}
it will only find your classes in the package com.myproject.a and it's children.
To solve this issue you must enhance the #ComponentScan in a way that it scans both package structures, eg.
package com.myproject.a
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = {"com.myproject.a", "com.myproject.b"}
// or basePackages = "com.myproject" in this example
class MyApp {
// Some public static void main ...
}

Resources