Jmockit/Spring mocked dependency still calls the Real dependency - spring

so I've been stuck on this problem all day.
I'm testing a class of type JdbcSupportDao in Spring 3.2. The problem is very self-explanatory if you just read the code, but I will briefly summarize:
I use the #Mocked annotation on a JdbcTemplate to mock querying the database. The problem is, after writing the Expectations block, the actual JdbcTemplate method is still being called, with JMockit apparently not entering in to the equation at all.
The following unit test fails:
/*#RunWith(SpringJUnit4ClassRunner.class)*/
#RunWith(JMockit.class)
#ContextConfiguration(locations={"classpath:studentAggregateReport-servlet.xml", "classpath:applicationContext-hibernate.xml"})
public class JdbcSSODaoTest extends AbstractTransactionalJUnit4SpringContextTests {
#Mocked
JdbcTemplate jdbcTemplate;
List<String> unameList;
SSODao ssoDao;
String DUMMY_ALCID = "yattayattayatta";
#Before
public void constructDao() {
this.ssoDao = new JdbcSSODao();
((JdbcSSODao) ssoDao).setJdbcTemplate(jdbcTemplate);
}
#Test
public void testGetUnameFromAlcId() {
unameList = new ArrayList<String>() {{
add("PEEPEE");
}};
//((JdbcSSODao) ssoDao).setJdbcTemplate(jdbcTemplate);
new Expectations() {{
jdbcTemplate.query(anyString, (ResultSetExtractor<String>)any); result = unameList;
}};
String uname = ssoDao.getUnameFromAlcId(DUMMY_ALCID);
assertNotNull(uname);
}
}
and here is the code for the class being tested:
public class JdbcSSODao extends JdbcDaoSupport implements SSODao {
#Override
public String getUnameFromAlcId(String alcid) {
String sql = SSOSqlUtil.createGetUnameByAlcIdSql(alcid);
logger.debug(sql);
List<String> resultLst = getJdbcTemplate().query(sql, new RowMapper<String>() {
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getString(1);
}
});
if(resultLst.isEmpty()) return null;
return resultLst.get(0);
}
}
Please help :(

Sweet mother of God..
Apparently, you have to cast parameters of mocked methods to the exact type used in the call. This fixed it for me:
new Expectations() {{
jdbcTemplate.query(anyString, (RowMapper<String>)any); result = unameList;
}};

Related

Why get java.sql.SQLException

I am developing a REST API Application for the first time and i was excited. Unfortunately, after the successful build, and when i run my application, i was facing error as below..
java.sql.SQLException: Invalid column index
at oracle.jdbc.driver.OraclePreparedStatement.setFormOfUseInternal(OraclePreparedStatement.java:10774) ~[ojdbc8-21.1.0.0.jar:21.1.0.0.0]
at oracle.jdbc.driver.OraclePreparedStatement.setFormOfUseInternal(OraclePreparedStatement.java:10755) ~[ojdbc8-21.1.0.0.jar:21.1.0.0.0]
Could you please help me fixing it. Thanks a lot in advance.
Here is the pieces of my code:
RestapiApplication.java
#SpringBootApplication
#ComponentScan(basePackages = "com.gfit.restapi")
#EnableSwagger2
public class RestapiApplication {
public static void main(String[] args) {
SpringApplication.run(RestapiApplication.class, args);
}
}
ModelEntity.java
/*#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "TEST_EMP")*/
public class ModelEntity {
/*#Id*/
private BigInteger track_id;
private BigInteger seq_num;
private String request_type;
private String certification_id;
private String student_id;
// constructor, getter, setter and tostring
}
GfitRESTRepositoryImpl.java
#Repository
public class GfitRESTRepositoryImpl implements GfitRESTRepository{
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public ModelEntity findById(String certification_id) {
try {
ModelEntity cert_detail = jdbcTemplate.queryForObject("SELECT track_id, seq_num, request_type, certification_id, STUDENT_ID FROM tbl_ep_stg_caa_ext WHERE certification_id = '' ",
BeanPropertyRowMapper.newInstance(ModelEntity.class), certification_id);
System.out.println(cert_detail);
return cert_detail;
} catch (IncorrectResultSizeDataAccessException e) {
return null;
}
}
}
GfitRESTController.java
#CrossOrigin(origins = "http://localhost:3000")
#RestController
#RequestMapping("/api")
public class GfitRESTController {
#Autowired
GfitRESTRepository gfitRESTRepository;
//#GetMapping("/certification/detail/{certification_id}")
#RequestMapping(value = "/certification/detail/{certification_id}", method = RequestMethod.GET)
public ResponseEntity<ModelEntity> getCertificateByID(#PathVariable("certification_id") String certification_id) {
ModelEntity cert_detail = gfitRESTRepository.findById(certification_id);
if (cert_detail != null) {
return new ResponseEntity<>(cert_detail, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
My Actual DB query gives the below result, and which i was trying to execute in my code above :
Postman screenshot :
Screenshots From Swagger-UI Endpoint :
Can you try downgrading the OJDBC JAR to version 12.2.0.1? I'm facing a similar issue with an update statement in my own application. We had upgraded to 21.1 a little while back from 12.2 and we never faced this issue with the 12.2 driver. I spent hours trying to figure it out and ended up reverting the driver version just to test it out and the error went away.
https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8/12.2.0.1

Cannot Write Data to ElasticSearch with AbstractReactiveElasticsearchConfiguration

I am trying out to write data to my local Elasticsearch Docker Container (7.4.2), for simplicity I used the AbstractReactiveElasticsearchConfiguration given from Spring also Overriding the entityMapper function. The I constructed my repository extending the ReactiveElasticsearchRepository
Then in the end I used my autowired repository to saveAll() my collection of elements containing the data. However Elasticsearch doesn't write any data. Also i have a REST controller which is starting my whole process returning nothing basicly, DeferredResult>
The REST method coming from my ApiDelegateImpl
#Override
public DeferredResult<ResponseEntity<Void>> openUsageExporterStartPost() {
final DeferredResult<ResponseEntity<Void>> deferredResult = new DeferredResult<>();
ForkJoinPool.commonPool().execute(() -> {
try {
openUsageExporterAdapter.startExport();
deferredResult.setResult(ResponseEntity.accepted().build());
} catch (Exception e) {
deferredResult.setErrorResult(e);
}
}
);
return deferredResult;
}
My Elasticsearch Configuration
#Configuration
public class ElasticSearchConfig extends AbstractReactiveElasticsearchConfiguration {
#Value("${spring.data.elasticsearch.client.reactive.endpoints}")
private String elasticSearchEndpoint;
#Bean
#Override
public EntityMapper entityMapper() {
final ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
entityMapper.setConversions(elasticsearchCustomConversions());
return entityMapper;
}
#Override
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(elasticSearchEndpoint)
.build();
return ReactiveRestClients.create(clientConfiguration);
}
}
My Repository
public interface OpenUsageRepository extends ReactiveElasticsearchRepository<OpenUsage, Long> {
}
My DTO
#Data
#Document(indexName = "open_usages", type = "open_usages")
#TypeAlias("OpenUsage")
public class OpenUsage {
#Field(name = "id")
#Id
private Long id;
......
}
My Adapter Implementation
#Autowired
private final OpenUsageRepository openUsageRepository;
...transform entity into OpenUsage...
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
And finally my IT test
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#Testcontainers
#TestPropertySource(locations = {"classpath:application-it.properties"})
#ContextConfiguration(initializers = OpenUsageExporterApplicationIT.Initializer.class)
class OpenUsageExporterApplicationIT {
#LocalServerPort
private int port;
private final static String STARTCALL = "http://localhost:%s/open-usage-exporter/start/";
#Container
private static ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:6.8.4").withExposedPorts(9200);
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(final ConfigurableApplicationContext configurableApplicationContext) {
final List<String> pairs = new ArrayList<>();
pairs.add("spring.data.elasticsearch.client.reactive.endpoints=" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
pairs.add("spring.elasticsearch.rest.uris=http://" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
TestPropertyValues.of(pairs).applyTo(configurableApplicationContext);
}
}
#Test
void testExportToES() throws IOException, InterruptedException {
final List<OpenUsageEntity> openUsageEntities = dbPreparator.insertTestData();
assertTrue(openUsageEntities.size() > 0);
final String result = executeRestCall(STARTCALL);
// Awaitility here tells me nothing is in ElasticSearch :(
}
private String executeRestCall(final String urlTemplate) throws IOException {
final String url = String.format(urlTemplate, port);
final HttpUriRequest request = new HttpPost(url);
final HttpResponse response = HttpClientBuilder.create().build().execute(request);
// Get the result.
return EntityUtils.toString(response.getEntity());
}
}
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
This lacks a semicolon at the end, so it should not compile.
But I assume this is just a typo, and there is a semicolon in reality.
Anyway, saveAll() returns a Flux. This Flux is just a recipe for saving your data, and it is not 'executed' until subscribe() is called by someone (or something like blockLast()). You just throw that Flux away, so the saving never gets executed.
How to fix this? One option is to add .blockLast() call:
openUsageRepository.saveAll(openUsages).blockLast();
But this will save the data in a blocking way effectively defeating the reactivity.
Another option is, if the code you are calling saveAll() from supports reactivity is just to return the Flux returned by saveAll(), but, as your doSomething() has void return type, this is doubtful.
It is not seen how your startExport() connects to doSomething() anyway. But it looks like your 'calling code' does not use any notion of reactivity, so a real solution would be to either rewrite the calling code to use reactivity (obtain a Publisher and subscribe() on it, then wait till the data arrives), or revert to using blocking API (ElasticsearchRepository instead of ReactiveElasticsearchRepository).

spring testing #async method

I'm trying to test if #Async annotation of Spring is working as expected on my project. But It doesn't.
I have this test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = GlobalConfiguration.class)
public class ActivityMessageListenerTest {
#Autowired
private ActivityMessageListener activityMessageListener;
private Long USER_ID = 1l;
private Long COMPANY_ID = 2l;
private Date DATE = new Date(10000000);
private String CLASSNAME = "className";
private Long CLASSPK = 14l;
private Integer TYPE = 22;
private String EXTRA_DATA = "extra";
private Long RECIVED_USER_ID = 99l;
#Before
public void setup() throws Exception {
}
#Test
public void testDoReceiveWithException() throws Exception {
System.out.println("Current thread " + Thread.currentThread().getName());
Map<String, Object> values = new HashMap();
values.put(ActivityMessageListener.PARAM_USER_ID, USER_ID);
values.put(ActivityMessageListener.PARAM_COMPANY_ID, COMPANY_ID);
values.put(ActivityMessageListener.PARAM_CREATE_DATE, DATE);
values.put(ActivityMessageListener.PARAM_CLASS_NAME, CLASSNAME);
values.put(ActivityMessageListener.PARAM_CLASS_PK, CLASSPK);
values.put(ActivityMessageListener.PARAM_TYPE, TYPE);
values.put(ActivityMessageListener.PARAM_EXTRA_DATA, EXTRA_DATA );
values.put(ActivityMessageListener.PARAM_RECEIVED_USER_ID, RECIVED_USER_ID);
Message message = new Message();
message.setValues(values);
MessageBusUtil.sendMessage(MKTDestinationNames.ACTIVITY_REGISTRY, message);
}
}
As you can see I'm printing the name of the current thread.
The class containing the #Async method is:
public class ActivityMessageListener extends BaseMessageListener {
public static final String PARAM_USER_ID = "userId";
public static final String PARAM_COMPANY_ID = "companyId";
public static final String PARAM_CREATE_DATE = "createDate";
public static final String PARAM_CLASS_NAME = "className";
public static final String PARAM_CLASS_PK = "classPK";
public static final String PARAM_TYPE = "type";
public static final String PARAM_EXTRA_DATA = "extraData";
public static final String PARAM_RECEIVED_USER_ID = "receiverUserId";
public ActivityMessageListener() {
MessageBusUtil.addQueue(MKTDestinationNames.ACTIVITY_REGISTRY, this);
}
#Override
#Async(value = "activityExecutor")
public void doReceive(Message message) throws Exception {
System.out.println("Current " + Thread.currentThread().getName());
if (1> 0)
throw new RuntimeException("lalal");
Map<String, Object> parameters = message.getValues();
Long userId = (Long)parameters.get(ActivityMessageListener.PARAM_USER_ID);
Long companyId = (Long)parameters.get(ActivityMessageListener.PARAM_COMPANY_ID);
Date createDate = (Date)parameters.get(ActivityMessageListener.PARAM_CREATE_DATE);
String className = (String)parameters.get(ActivityMessageListener.PARAM_CLASS_NAME);
Long classPK = (Long)parameters.get(ActivityMessageListener.PARAM_CLASS_PK);
Integer type = (Integer)parameters.get(ActivityMessageListener.PARAM_TYPE);
String extraData = (String)parameters.get(ActivityMessageListener.PARAM_EXTRA_DATA);
Long receiverUserId = (Long)parameters.get(ActivityMessageListener.PARAM_RECEIVED_USER_ID);
ActivityLocalServiceUtil.addActivity(userId, companyId, createDate, className, classPK, type, extraData, receiverUserId);
}
}
Here I'm printing the name of the current thread inside of the #Async method, and the name is the same as before, main. So it's not working.
The GlobalConfiguration is:
#Configuration
#EnableAspectJAutoProxy
#EnableTransactionManagement
#ComponentScan({
"com.shn.configurations",
...some packages...
})
public class GlobalConfiguration {...}
And inside one of the specified packages has the activityExecutor bean:
#Configuration
#EnableAsync(proxyTargetClass = true)
public class ExecutorConfiguration {
#Bean
public ActivityMessageListener activityMessageListener() {
return new ActivityMessageListener();
}
#Bean
public TaskExecutor activityExecutor()
{
ThreadPoolTaskExecutor threadPoolTaskExecutor =
new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(10);
threadPoolTaskExecutor.setQueueCapacity(100);
return threadPoolTaskExecutor;
}
}
What I'm doing wrong?
Tricky.
Asynchronous behavior is added through proxying.
Spring provides you with a proxy that wraps the actual object and performs the actual invocation in a separate thread.
It looks something like this (except most of this is done dynamically with CGLIB or JDK proxies and Spring handlers)
class ProxyListener extends ActivityMessageListener {
private ActivityMessageListener real;
public ProxyListener(ActivityMessageListener real) {
this.real = real;
}
TaskExecutor executor; // injected
#Override
public void doReceive(Message message) throws Exception {
executor.submit(() -> real.doReceive(message)); // in another thread
}
}
ActivityMessageListener real = new ActivityMessageListener();
ProxyListener proxy = new ProxyListener(real);
Now, in a Spring world, you'd have a reference to the proxy object, not to the ActivityMessageListener. That is
ActivityMessageListener proxy = applicationContext.getBean(ActivityMessageListener.class);
would return a reference to the ProxyListener. Then, through polymorphism, invoking doReceive would go to the overriden Proxy#doReceive method which would invoke ActivityMessageListener#doReceive through delegation and you'd get your asynchronous behavior.
However, you're in a half Spring world.
Here
public ActivityMessageListener() {
MessageBusUtil.addQueue(MKTDestinationNames.ACTIVITY_REGISTRY, this);
}
the reference this is actually referring to the real ActivityMessageListener, not to the proxy. So when, presumably, you send your message on the bus here
MessageBusUtil.sendMessage(MKTDestinationNames.ACTIVITY_REGISTRY, message);
you're sending it to the real object, which doesn't have the proxy asynchronous behavior.
The full Spring solution would be to have the MessabeBus (and/or its queue) be Spring beans in which you can inject the fully process (proxied, autowired, initialized) beans.
In reality, since CGLIB proxies are really just subclasses of your types, so the ProxyListener above would actually also add itself to the bus since the super constructor would be invoked. It would seem though that only one MessageListener can register itself with a key, like MKTDestinationNames.ACTIVITY_REGISTRY. If this isn't the case, you'd have to show more of that code for explanation.
In your test, if you do
activityMessageListener.doReceive(message);
you should see that asynchronous behavior since activityMessageListener should hold a reference to the proxy.

NullPointerException TopLevelTransaction.markAsRollbackOnly Neo4J-Boot for findAll() method

I am trying to follow Josh Long - Philip Sorst example in order to perform Angular SPA-Rest Authentication and CRUD actions using Neo4J as db (excellent work. Thanks a lot guys). But I am stuck at a very early stage and I suspect it's not my fault. Please help Neo4J-Angular-Spring lovers. My code can be found here and it is very easy to run just clone and give mvn spring-boot:run
Now the problem is that I get the following exception only for the findAll() method of the GraphRepository.
Caused by: java.lang.NullPointerException: null
at org.neo4j.kernel.TopLevelTransaction.markAsRollbackOnly(TopLevelTransaction.java:93)
... 88 common frames omitted
and I will replicate some of my code:
Neo4JConfig.java
#Configuration
#EnableNeo4jRepositories(basePackages = "demo.repository.neo4j")
public class Neo4JConfig extends Neo4jConfiguration {
public Neo4JConfig() {
setBasePackage("demo.model.neo4j");
}
#Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("data/demo.db");
}
#Bean
public Neo4jTemplate neo4jTemplate() {
return new Neo4jTemplate(graphDatabaseService());
}
}
NewsEntry.java
#NodeEntity
public class NewsEntry {
#GraphId
private Long id;
private String content;
public NewsEntry() {}
public NewsEntry(String b) {
this.content = b;
}
public Long getId() {
return this.id;
}
public String getContent() {
return this.content;
}
public void setId(Long id) {
this.id = id;
}
public void setContent(String content) {
this.content = content;
}
}
NewsEntryRepository.java
public interface NewsEntryRepository extends GraphRepository<NewsEntry> {
}
NewsEntryController.java
#RestController
class NewsController {
#Autowired
private NewsEntryRepository newsEntryRepository;
#RequestMapping("/news")
List<NewsEntry> entries() {
List<NewsEntry> list = new ArrayList<NewsEntry>();
Iterable<NewsEntry> results = newsEntryRepository.findAll();
for (NewsEntry r : results) {
list.add(r);
}
return list;
}
#RequestMapping(value = "/news/{id}", method = RequestMethod.DELETE)
void remove(#PathVariable Long id) {
this.newsEntryRepository.delete(id);
return;
}
#RequestMapping(value = "/news/{id}", method = RequestMethod.GET)
NewsEntry entry(#PathVariable Long id) {
return this.newsEntryRepository.findOne(id);
}
#RequestMapping(value = "/news/{id}", method = RequestMethod.POST)
NewsEntry update(#PathVariable Long id, #RequestBody NewsEntry news) {
NewsEntry old = this.newsEntryRepository.findOne(id);
old = news;
return this.newsEntryRepository.save(old);
}
#RequestMapping(value = "/news", method = RequestMethod.POST)
NewsEntry add(#RequestBody NewsEntry news) {
this.newsEntryRepository.save(new NewsEntry(news.getContent()));
return news;
}
}
OK Solution inspired from here https://github.com/mstahv/bootiful-neo4j-with-vaadin/blob/master/src/main/java/org/vaadin/neo4j/AppService.java. He is implementing a #Service annotated with #Transactional before using the repository in the controller.
You shouldn't have to override:
#Bean
public Neo4jTemplate neo4jTemplate() {
return new Neo4jTemplate(graphDatabaseService());
}
And can you try to add the annotation:
#EnableTransactionManagement
to your config?
Something is telling me that the solution is hiding somewhere here. I will give it a go and let you know.
OK This works only if you change the version of Spring-data-neo4j to 2.3.3.RELEASE. If you use the latest version you get the same problem as above. I think I should open an issue.
But that's not the solution as I would like to use Neo4J Server Community 2.0.3 to open the graph for visualization afterwards. Also I do not understand this solution beanfactories, injects instead of autowired???. However I will make another branch for this solution in my github repo.

Using session in old Petclinic example

I'm experimenting with the old Petclinic example and I noticed that the vets ArrayList in the SimpleJdbcClinic exists for the life of the session. It seems like it should exist only for the request since I don't see any annotations putting it into the session context. Could someone point out what I'm failing to understand?
Here is the vets class:
#XmlRootElement
public class Vets {
private List<Vet> vets;
#XmlElement
public List<Vet> getVetList() {
if (vets == null) {
vets = new ArrayList<Vet>();
}
return vets;
}
}
The service:
#Service
#ManagedResource("petclinic:type=Clinic")
public class SimpleJdbcClinic implements Clinic, SimpleJdbcClinicMBean {
private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertOwner;
private SimpleJdbcInsert insertPet;
private SimpleJdbcInsert insertVisit;
private final List<Vet> vets = new ArrayList<Vet>();
:
:
#Transactional(readOnly = true)
public Collection<Vet> getVets() throws DataAccessException {
synchronized (this.vets) {
if (this.vets.isEmpty()) {
refreshVetsCache();
}
return this.vets;
}
}
}
The controller mapping:
#RequestMapping("/vets")
public ModelMap vetsHandler() {
Vets vets = new Vets();
vets.getVetList().addAll(this.clinic.getVets());
return new ModelMap(vets);
}
Once the vets list is created it survives multiple requests.
Thanks
I think it avoids redundant database calls by storing all vets in the private final List<Vet> vets. Also vets variable is a property of a singleton #Service SimpleJdbcClinic

Resources