How to avoid SonarLint UnusedPrivateMethod when instantiating Spring components? - java

In a basic Spring Boot app I have this component:
#Component
public class TheComponent {
public String getKey() {return "value";}
}
used by a service. If I design my service like this:
#Service
public class TheService {
#Autowired
private TheComponent theComponent;
private final String keyValue = theComponent.getKey();
private TheService() {}
}
then Spring Boot doesn't build because theComponent triggers a NullPointerException.
If I design it like this:
#Service
public class TheService {
private String keyValue;
private TheService(TheComponent theComponent) {
keyValue = theComponent.getKey();
}
}
then SonarLint tells me that I should Remove this unused private "TheService" constructor.
Is there a solution that would suit both Spring and SonarLint, using a private constructor ?

Annotate your constructor with:
#SuppressWarnings("unused")
You can also use it on class level to suppress all warnings.

Related

How to mock usage of component in #value annotation of JPA request model?

I have the following code, and I was wondering how to mock the component used in the value annotation. It is not instantiated in the model class, so I can't really use the annotation #InjectMocks, how do I perform a mock in this context?
public interface Vehicule {
#Value('#{target.VEHICULE_ID}')
BigInteger getId();
#Value('#{#mapperUtility.clobToString(target.CERTIFICATE)}') // How to mock this call?
String getCertificate();
}
#Component
public class MapperUtility {
public String clobToString(Clob clob) {
return (clob == null) ? null : ClobType.INSTANCE.toString(clob); // from org.hibernate.type
}
}
public interface VehiculeRepository extends JpaRepository<Vehicule, String> {
#Query(value = SQL_QUERY_FIND_VEHICULE_BY_IDS)
List<Vehicule> findVehiculeByIds(#Param("Ids") List<BigInteger> ids);
}
What would a test that mocks the component inside the value annotation would look like?
This is a pretty common issue when using direct field injection. We solved this problem by writing a Junit5 extension: http://github.com/exabrial/mockito-object-injection
This allows you to cleanly inject data into private members of a class under test, without resorting to fire up an entire container for an integration test.
Example:
#TestInstance(Lifecycle.PER_CLASS)
#ExtendWith({ MockitoExtension.class, InjectExtension.class })
class MyControllerTest {
#InjectMocks
private MyController myController;
#Mock
private Logger log;
#Mock
private Authenticator auther;
#InjectionSource
private Boolean securityEnabled;
#Test
void testDoSomething_secEnabled() throws Exception {
securityEnabled = Boolean.TRUE;
myController.doSomething();
// wahoo no NPE! Test the "if then" half of the branch
}

Autowiring any of an Interface using Spring Boot

I want autowire a class which implements in a Component. Here is a part of the interface:
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class GenericResourceHandlerService<T extends ResourceRequest, A extends ResultType, B extends ResourceService<T, A>> {
private final B service;
public Response get(String x) {
various checks(x, service.getType());
B res = service.get(x);
if (res!= null) {
return Response.status(Response.Status.OK).entity(res).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}
Then, a class which implements ResourceService would look like this:
#Component
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class TypeOneService implements EntityService<CityRequest, City> {
private final Repository repository;
#Override
public ResultType getType() {
return ResultType.TYPE_ONE;
}
#Timed
public TYPE_ONE get(String resource) {
return repository.get(resource);
}
}
And the interface itself, looks like this:
public interface EntityService<T extends EntityRequest, A extends ReturnableEntity> {
ResourceType getResourceType();
A get(String resource);
}
Now, I have a set of controllers which tries to autowire GenericResourceHandlerService and call it's get method. Which looks like this:
public class TypeOneController {
private final TypeOneService typeOneService;
private final GenericResourceHandlerService<TypeOneRequest, TypeOne, TypeOneService> genericResourceHandlerService;
public Response getListItemByResource(
String resource
) {
return genericResourceHandlerService.get(resource);
}
}
Or this:
public class TypTwoController {
private final TypeTwoService typeTwoService;
private final GenericResourceHandlerService<TypeTwoRequest, TypeTwo, TypeTwoService> genericResourceHandlerService;
public Response getListItemByResource(
String resource
) {
return genericResourceHandlerService.get(resource);
}
}
This compiles but when the app starts then, then I get the following error message:
Parameter 0 of constructor in path.GenericResourceHandlerService required a single bean, but 2 were found:
- typeOneSerivce: defined in file [C:\Path\TypeOneService.class]
- typeTwoService: defined in file [C:\Path\TypeTwoService.class]
I think this is because, Spring Boot can't work out which one to service to autowire with. Is it possible what I am trying to do?
Spring tries to inject a bean to resolve the GenericResourceHandlerService.service but service has type B and B extends ResourceService. And spring found 2 beans implementing this interface so doesn't know which implementation to autowire..
You can put #Qualifier on field service but I imagine you will lost the genericity of this type GenericResourceHandlerService
Maybe the best way is to let the controller pass through the implementation in the GenericResourceHandlerService and let this last as a simple pojo..not a spring bean (so remove #Service on GenericResourceHandlerService
Like this
public class TypeOneController {
#Autowired
private final TypeOneService typeOneService;
private final GenericResourceHandlerService<TypeOneRequest, TypeOne, TypeOneService> genericResourceHandlerService = new GenericResourceHandlerService(typeOneService);
public Response getListItemByResource(
String resource
) {
return genericResourceHandlerService.get(resource);
}
}

Inject value from properties in Spring Boot

I have a Rest Controller in which I initialise a service like this :
class Config {
#Value(${"number.of.books"})
private final static String numberOfBooks;
}
class MyController {
private final Service myService = new ServiceImplementation(Config.numberOfBooks)
public ResponseEntity methodA() { ... }
}
The numberOfBooks field has a initialisation value but when it's passed in the ServiceImplementation constructor it comes null.
I'm thinking I'm missing something obvious over here.
What is the mistake and which would be the best practice to inject a value from a property file into a constructor?
I recommend you to directly inject numberOfBooks in your ServiceImplementation, as follows:
public class ServiceImplementation implements Service {
#Value("${number.of.books}")
private String numberOfBooks;
}
Otherwise use setter injection for static variables, as follows:
#Component
class Config {
public static String numberOfBooks;
#Value("${number.of.books}")
public void setNumberOfBooks(String numberOfBooks) {
numberOfBooks = numberOfBooks;
}
}
After studying a little I've found out that the dependency injection happens after the constructor has been called. This being said the approach used was to use Autowired on my services constructor.
class ServiceImplementation implements Service {
private final String numberOfBooks;
#Autowired
private ServiceImplementation(Config config) {
this.numberOfBooks = config.getNumberOfBooks();
}
}
In this way Spring creates the dependency tree and makes sure that Config is not null when injected.

How to use Singleton object in Spring?

I am newbie to Spring Framework.I have tried following example in spring.
#Path("/XZY")
#Service
#Transactional
public class XZY {
#Autowired
SampleDAO sampleDao;
#Autowired
TestDAO testDao;
#Autowired
XZYinterface xzyinterface;
#POST
#Produces("text/plain")
#Path("/checkservice")
public Response XZYservice(#FormParam("Code") String Code,
#FormParam("source") String source,
#FormParam("value") String value) {
//return xzyinterface.checkXYZService(Code,sourceName,source);
XZYinterface xyz = ServiceFactory.getXZY(999);
return xyz.checkXYZService(Code,sourceName,source);
}
}
The following code will use to create singleton object
public class Singleton {
private static sampleA sampleClassA=null;
private static SampleB sampleClassB=null;
public static XZYAbstract getXZY(long id){
if(id == 999){
if(sampleClass == null){
sampleClassA = new sampleA();
}
return sampleClass;
}
if(id == 9999){
sampleClassB = new sampleA();
}
return sampleClassB;
}
}
Interface
public interface XZYinterface {
Response XZYservice(String Code, String source,String value)
}
Abstract class and implements Interface
public class XZYAbstract implements XZYinterface {
public XZYAbstract(){
super();
}
#Autowired
SampleDAO sampleDao;
#Autowired
TestDAO testDao;
public Response checkXYZService(String Code,String source,String value){
String sample = sampleDao.getValue(code);
//..source code
}
}
The following class extends abstract class.
public class sampleA extends XZYAbstract {
//some methods.
}
If i run the application it throws following errors
SEVERE [com.sun.jersey.spi.container.ContainerResponse] The RuntimeException could not be mapped to a response, re-throwing to the HTTP container: java.lang.NullPointerException
at com.test.xyz.XZYAbstract.checkXYZService(XZYAbstract.java:112) [:]
at com.test.XYZ.XZYservice(XZY.java:140) [:]
If i call directly without singleton object, values are initialized properly using Auto wired (//return xzyinterface.checkXYZService(Code,sourceName,source);) and it's working fine.
Throw from singleton object, values(sampleDAo,testDao) are not initialized properly.
How to resolve this error?
The reason is quite trivial: it's because Spring is just a library, and not a change to the Java language. Spring doesn't instrument nor enhance constructors, so the only way to get initialized Spring bean is to get it from the Spring context.
If you call new Bean(), you becomes Bean instance untouched by Spring.
For the question how to use singleton bean: do nothing. Spring beans are Singletons by default. You can specify other scope via #org.springframework.beans.factory.config.Scope annotation. See for example #Scope("prototype") bean scope not creating new bean, how it works.

Is it common to have dependency between facade layer?

My application have the follow layer:
- Facade
- Business Object
- Repository (Spring JPA Data)
Let's suppose the follow classes:
#Component
public class MessageFacade implements MessageService {
#Autowired
private GarageBO garageBO;
#Autowired
private MessageBO messageBO;
public void createFeedbackMessage(...) {
messageBO.createFeedbackMessage(...);
garageBO.createFeedback(...);
}
}
#Component
public class ServiceOrderFacade implements ServiceOrderService {
#Autowired
private ServiceOrderBO serviceOrderBO;
#Autowired
private MessageBO messageBO;
#Autowired
private GarageBO garageBO;
public void createServiceOrder(...) {
serviceOrderBO.createServiceOrder(...);
messageBO.createFeedbackMessage(...);
garageBO.createFeedback(...);
}
}
Observing the createFeedbackMessage method in MessageFacade i have:
1) The createFeedbackMessage method in MessageBO it's responsible to create an email with the feedback survey LINK;
2) The createFeedbackMessage method in garageBO creates the Feedback ENTITY with the questions and responses;
On createServiceOrder method in ServiceOrderFacade i need to call an method of ServiceOrderBO and after i need to have the same behavior of createFeedbackMessage method in MessageFacade.
Is it a bad idea to create a dependency between ServiceOrderFacade -> MessageFacade ?
The code would be:
#Component
public class ServiceOrderFacade implements ServiceOrderService {
#Autowired
private ServiceOrderBO serviceOrderBO;
#Autowired
private MessageBO messageBO;
#Autowired
private GarageBO garageBO;
public void createServiceOrder(...) {
serviceOrderBO.createServiceOrder(...);
getMessageService().createFeedbackMessage(...);
}
}
If you think in DRY(don't repeat yourself) you have an problem. You can create another layer like a common that is dependency of Business Object layer and will be created once and will be used in your entire BO if U want

Categories

Resources