I've got a method called getBillingCodes that returns a List of objects called BillingCodes.
#Service
public class BillingCodeService {
private static final Logger log = LoggerFactory.getLogger(BillingCodeService.class);
String sql;
#Autowired
private BillingCodeRowMapper billingCodeRowMapper;
#Autowired
private JdbcTemplate jdbcTemplate;
public List<BillingCode> getBillingCodes(int billingCodeId, int limit) {
sql = [SQL_STATEMENT]";
List<BillingCode> billingCodeList;
billingCodeList = jdbcTemplate.query(sql, new Object[]{billingCodeId, limit}, billingCodeRowMapper);
return billingCodeList;
}
}
I would like to change the getBillingCodes method so that it still returns a List of objects but I like to specify the List of objects in a class like this
#Component
public class BillingCodeList {
private List<BillingCode> billingCodeList;
Getter and Setters removed,,.
}
And then change the change the getBillingCodes method to:
#Service
public class BillingCodeService {
private static final Logger log = LoggerFactory.getLogger(BillingCodeService.class);
String sql;
#Autowired
private BillingCodeRowMapper billingCodeRowMapper;
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private BillingCodeList billingCodeList;
public BillingCodeList getBillingCodes(int billingCodeId, int limit) {
sql = "[SQL_STATEMENT]";
billingCodeList = jdbcTemplate.query(sql, new Object[]{billingCodeId, limit}, billingCodeRowMapper);
return billingCodeList;
}
}
Setting billingCodeList = jdbcTemplate.query,,. gives me an error no instance(s) of variable(s) T exist so that List<T> conforms to BillingCodeList. Therefore I've tried to cast the List<T> to BillingCodeList like this:
billingCodeList = (BillingCodeList)jdbcTemplate.query(sql, new Object[]{billingCodeId, limit}, billingCodeRowMapper);
But that gives me a casting error java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.test.model.BillingCodeList. How can I cast java.util.ArrayList to com.test.model.BillingCodeList
You can not cast List to a class object.One thing you can do you can pass BillingCodeList object to BillingCodeRowMapper through constructor and populate the BillingCodeList after creating the BillingCode.
You don't want to do what you're asking (in effect, you're have an XY problem moment).
To explain, I see that BillingCodeList is annotated with #Component, which I'm guessing means that it's a Spring component - and you need to do some very fancy footwork to make this work (and it would be inefficient as hell).
I'm guessing that you don't want to re-read all the billing codes each time, and instead you want to cache them in memory. In this case, something like this will work better:
#Component
public class BillingCodeListCache {
#Autowired
private BillingCodeService billingCodeService;
private List<BillingCode> billingCodeList;
public List<BillingCode> getBillingCodes() {
if(billingCodeList == null) {
billingCodeList = billingCodeService.getBillingCodes();
}
return billingCodeList; // -- or a sublist.
}
}
This way you can also control cache eviction.
If the only reason you are doing this is to have a method to print out the values of the list, then just extend ArrayList or implement the List interface in your class. Then you can override the toString method to do what you want.
I went with the solution suggested by Lew Bloch. Passing the List as an argument in the BillingCodes constructor.
#Autowired
private BillingCodes billingCodesToString(List<BillingCode> billingCodes) {
return new BillingCodes(billingCodes);
}
And then overriding the toString() method in the BillingCodes class giving me the ability to to get the String like so:
billingCodesToString(billingCodes).toString()
Related
I have a Util class and there is a static method called csvToEmployees. In order to use this method with different type of request classes, I am trying to convert the class as shown below that takes generic parameter:
public class CsvHelper<T> {
public List<T> csvToEmployees(InputStream is) {
//code omitted
for (CSVRecord rec : records) {
T employee = new T(
// ...
);
employees.add(employee);
}
return employees;
}
}
I call this method from my service by injecting this util class as shown below:
#Service
#RequiredArgsConstructor
public class EmployeeService {
private final EmployeeRepository employeeRepository;
private final CsvHelper<EmployeeRequest> helper;
public void create(MultipartFile file) {
List<Employee> employees = helper.csvToEmployees(file.getInputStream()).stream()
.map(EmployeeRequestMapper::mapToEntity)
.toList();
// ...
}
}
My problems are:
1. Is the implementation approach above is ok or not? I mean assuming that there are different kind of requests with the same fields, is using generic with that approach ok?
2. I get "Type parameter 'T' cannot be instantiated directly" error in the T employee = new T( line of util class. How can I fix it?
The best solution, in my opinion, is just creating multiple csvToObject methods inside the classes that you need to process.
I mean if you already know that you’re transforming a stream into a list of employees (it’s “hard coded” in the service method) why would you need to use generics? Just use the method for employees instead.
Class to be tested
public class KnockoutValidation {
public boolean runFormValidation(String param1, boolean param1, final String param3) {
//...
AccessBeanFactory fact = new AccessBeanFactory();
AccessBean bean = (AccessBean) fact.getAccessBean("abc", "xyz");
//....
}
}
Test Class
#RunWith(MockitoJUnitRunner.class)
public class KnockOutValidationTest {
#InjectMocks
KnockoutValidation KnockoutValidationMock;
#Mock
AccessBeanFactory factMock;
AccessBean accessBean;
#Before
public void setUp() {
accessBean = new AccessBean();
when(factMock.getAccessBean(anyString(), anyString())).thenReturn(accessBean);
}
#Test
public void doKnockoutValidationTest() {
Boolean result = KnockoutValidationMock.runFormValidation("a", true, "c");
Assert.assertEquals(result, true);
}
}
Even after mocking it is calling the actual implementation and throwing an exception and getting
java.lang.NullPointerException
ideally when we mock it should not execute actual method, here it is going into that getAccessBean method which is again a big API with a lot of try and catch blocks. So somewhere inside it is throwing an exception.
I just want to know why mocking is not working and how to mock this type of casted methods
I believe the way you had written implementation, it won't be possible reason is
AccessBeanFactory fact= new AccessBeanFactory();
instead you can
#Autowired private AccessBeanFactory fact;
Problem :- Every-time you call fact.getAccessBean with newly created object(instead of mock) while beans are not available. So it does throw NPE as expected
The #InjectMock won't work in this case because you are creating the AccessBeanFactory in place with a new constructor.
AccessBeanFactory fact= new AccessBeanFactory();;
You should have it as a field of the class, then the InjectMock will work, or better pass the factory as an argument.
Here is one example that should work. #InjectMock works by type, meaning that it will search through the class's field with Reflection and injects the mocks you specify with the #Mock annotation.
public class KnockoutValidation {
#Autowired
AccessBeanFactory fact;
public boolean runFormValidation(String param1, boolean param1, final String param3) {
//...
AccessBean bean = (AccessBean) fact.getAccessBean("abc", "xyz");
//....
}
}
You could also try to use PowerMockito's whenNew that will actually apply to the inline class creation, but that's a dark path you should avoid and only use with 3rd party codes.
I have a #Service class which is called from a web request.
It has a constructor which initializes the list of objects of an implemented type
private List<Interface> interfaceServices;
#Autowired
public ValidateInterfaceService(List<Interface> interfaceServices) {
this.interfaceServices = interfaceServices;
}
This works as intended except if one of the items in the list has a constructor.
#Service
#Order(3)
public class EvaluateExampleWithConstructor implements Interface {
private LocalDate busDate;
#Autowired
public EvaluateExampleWithConstructor(LocalDate busDate) {
this.busDate = busDate;
}
If I try and have this class on the list the code cannot run as "no default constructor is found"
If the value passed into the constructor is needed for the method how do I initialize this list correctly?
Your problem is caused by the private LocalDate busDate not being a bean in the context. You can create a LocalDate for injection like this:
#Configuration
public class FooConfiguration {
#Bean
public LocalDate busDate() {
return ...
}
}
Note this looks rather weird, and you might be better off initializing this date in a different way, depending on your use-case, e.q. using #Value.
I am trying to unit test a void method which gets data from database, formats into map and passes onto another class.
I have mocked out the database call and returned my own data, and I want to inspect the map which has been formatted contains the right number of elements and keys in right locations.
I have tried playing around with argumentCaptor to do this but struggling to get my head round it.
Method to test:
public class MyClass {
#Autowired
private Dao dao;
#Autowired
private AnotherClass anotherClass;
public void format(String, Date) {
Map<Object,Object> map = getDataAndFormat(String, Date);
anotherClass.doSomething(map);
}
private Map<Object, Object> getDataAndFormat(String, Date) {
Map map;
if (String.equals("A") {
map = dao.getData(Date);
}
else {
map = dao.getDataSomeThingElse(Date);
}
}
}
Any help much appreciated
Thanks,
so: This is what I have so far:
#InjectMocks
#Autowired
//class to test
private MyClass myClass;
#Mock
Dao dao;
#Captor
private ArgumentCaptor<String> argumentCaptor;
#Captor
private ArgumentCaptor<Date> argumentCaptorB;
public void testFormat()
{
when(dao.getData(Matchers.any())).thenReturn(data());
myClass.format("A",new Date());
}
So i want to use argument captors (but not entirely sure how to) to get the map from the format method call and inspect the returned map. The code i currently have is hitting all my code but I can't assert on anything hence why i wanted to check the map contains what I expect it to. Hope that makes sense
It appears that what you want to do is to confirm the contents of the map that is passed to AnotherClass.
If AnotherClass is an interface, you can create a mock instance of AnotherClass and inject it into your MyClass. You can then verify that it has been called with your arguments of choice:
Mockito.verify(mockAnotherClass).doSomething(expectedMap);
I have a StoredProcedure which is compiled on initialization.
Occasionally the logic requires that I use a different stored procedure.
I have tried and failed to reset the name of the stored procedure. The data is still retrieved using the original stored procedure.
Is there a way to achieve this?
Here is a reduced version of the class showing initialization and attempted recompiling with the name of a different stored procedure:
import org.springframework.jdbc.object.StoredProcedure;
public class MyDAOImpl extends StoredProcedure implements MyDAO {
#Autowired
public MyDAOImpl(DataSource dataSource, String originalSPName) {
super(dataSource, originalSPName); // invokes StoredProcedure constructor
compile();
}
public List<String> useOtherStoredProcedure(){
super.setSql("otherSPName");
compile();
// Error: Data is still retrieved with original StoredProcedure name
Map<String, Object> data = this.executeSP();
}
}
Rather than org.springframework.jdbc.object.StoredProcedure pls use org.springframework.jdbc.core.simple.SimpleJdbcCall. The beauty of SimpleJdbcCall is that you can dynamically specify the schema, package and stored procedure names. Pls find the respective code below :-
#Autowired
private JdbcTemplate jdbcTemplate;
public Date getSPData() {
SimpleJdbcCall spCall = new SimpleJdbcCall(jdbcTemplate).withSchemaName("schema")
.withCatalogName("catalog")
.withProcedureName("proc")
.withoutProcedureColumnMetaDataAccess()
.useInParameterNames("ref_id")
.declareParameters(
new SqlParameter("ref_id", Types.NUMERIC),
new SqlOutParameter("dt", Types.DATE));
SqlParameterSource in = new MapSqlParameterSource()
.addValue("ref_id", 12345);
Map<String, Object> out = spCall.execute(in);
Date date = (Date) out.get("dt");
return date;
}
I believe this might be what you want:
public class MyDAOAdapter implements MyDAO {
private volatile MyDAO currentDao;
private final MyDAO myDAOImpl1;
private final MyDAO myDAOImpl2;
#Autowired
public MyDAOImpl(#Qualifier("myDAOImpl1") MyDAO myDAOImpl1, #Qualifier("myDAOImpl2") MyDAO myDAOImpl2) {
this.myDAOImpl1 = myDAOImpl1;
this.myDAOImpl2 = myDAOImpl2;
currentDao = myDAOImpl1;
}
public void switchToFirstDao() {
currentDao = myDAOImpl2;
}
public void switchToSecondDao() {
currentDao = myDAOImpl2;
}
// do you really need this?
public List<String> useOtherStoredProcedure(){
return myDAOImpl2.executeSP();
}
// Delegate all the methods to current DAO selected
public List<String> executeSP(){
return currentDao.executeSP();
}
// implement all other methods by delegating calls to currentDao
}
This should be autowired by all the code and the switch between the two StoredProcedure implementations would be hidden inside this adapter. Still I didn't understand if you want this switch to be global for all code or only for some cases.
The solution I found for my own situation was to implement a third stored procedure on SQL Studio, which acts as a common accessor and routes the query to the right stored procedure based on a parameter.
CREATE PROCEDURE [dbo].[Router_SP]
#spNumber as INTEGER
AS
BEGIN
IF(#spNumber = 1) EXECUTE originalSPName
ELSE IF (#spNumber = 2) EXECUTE otherSPName
ELSE RETURN 'Unrecognised stored procedure'
END
Leaving this question open for now to see if a better solution comes up.