Querydsl + Spring + Transactional ignored - java

I want to confirm rollback behavior, but I'm having trouble getting it to work.
I have a postgres DB with the following tables:
select * from cat;
pkid | name
--------------------------------------+-------
c75d6e8b-6aff-4214-ad45-d17db254857b | Abbey
select * from toy;
pkid | name | description
--------------------------------------+---------------+-------------------------------------------
dda72782-a1aa-4c0e-9cf6-a408db58a1ae | Laser pointer | Red laser.
f4d7e67d-1b26-4d8d-bb98-1a5c69f3cb49 | String | Colored string attached to a plastic rod.
select * from cattoy;
pkid | fkcat | fktoy
------+-------+-------
I have created a CatService implementation with the idea being you can create a cat, toy, and associate that toy with that cat. If any one of the 3 operations fails I want them all to rollback.
DefaultCatService.java:
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.dao.CatDao;
import com.bonkeybee.dao.CatToyDao;
import com.bonkeybee.dao.ToyDao;
import com.bonkeybee.querydsl.Cat;
import com.bonkeybee.querydsl.Cattoy;
import com.bonkeybee.querydsl.Toy;
#Inject
private CatDao catDao;
#Inject
private CatToyDao catToyDao;
#Inject
private ToyDao toyDao;
#Override
#Transactional
public UUID createCat(final Cat cat){
LOG.debug("Creating cat");
UUID catPkid = catDao.createCat(cat);
Toy toy = new Toy();
toy.setName("Box");
toy.setDescription("Cardboard box.");
toy.setPkid(toyDao.createToy(toy));
Cattoy catToy = new Cattoy();
catToy.setFkcat(catPkid);
catToy.setFktoy(toy.getPkid());
catToyDao.createCatToy(catToy);
return catPkid;
}
I have created DAO's and their implementations for each table with basic CRUD operations.
CatDaoJdbc.java:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.Cat;
import com.bonkeybee.querydsl.QCat;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.SimplePath;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.sql.SQLQueryFactory;
private static final QCat CAT = QCat.cat;
private static final SimplePath<Object> CAT_PKID = CAT.pkid;
private static final StringPath CAT_NAME = CAT.name;
#Inject
private SQLQueryFactory sqlQueryFactory;
#Override
public UUID createCat(final Cat cat) {
UUID catPkid = UUID.randomUUID();
sqlQueryFactory.insert(CAT)
.columns(CAT_PKID, CAT_NAME)
.values(catPkid, cat.getName())
.execute();
return catPkid;
}
ToyDaoJdbc.java
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.QToy;
import com.bonkeybee.querydsl.Toy;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.SimplePath;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.sql.SQLQueryFactory;
private static final QToy TOY = QToy.toy;
private static final SimplePath<Object> TOY_PKID = TOY.pkid;
private static final StringPath TOY_NAME = TOY.name;
private static final StringPath TOY_DESCRIPTION = TOY.description;
#Inject
private SQLQueryFactory sqlQueryFactory;
#Override
public UUID createToy(Toy toy) {
UUID toyPkid = UUID.randomUUID();
sqlQueryFactory.insert(TOY)
.columns(TOY_PKID, TOY_NAME, TOY_DESCRIPTION)
.values(toyPkid, toy.getName(), toy.getDescription())
.execute();
return toyPkid;
}
CatToyDaoJdbc.java:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.Cattoy;
import com.bonkeybee.querydsl.QCat;
import com.bonkeybee.querydsl.QCattoy;
import com.bonkeybee.querydsl.QToy;
import com.bonkeybee.querydsl.Toy;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.SimplePath;
import com.querydsl.sql.SQLQueryFactory;
#Override
public UUID createCatToy(Cattoy catToy) {
throw new RuntimeException("Simulating exception");
}
Main.java:
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.Cat;
import com.bonkeybee.querydsl.Cattoy;
import com.bonkeybee.querydsl.Toy;
import com.bonkeybee.service.CatService;
import com.bonkeybee.service.CatToyService;
import com.bonkeybee.service.ToyService;
public static void main(String[] args) {
try (ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfiguration.class)) {
CatService catService = applicationContext.getBean(CatService.class);
Cat newCat = new Cat();
newCat.setName(DORA);
newCat.setPkid(catService.createCat(newCat));
}
}
ApplicationConfiguration.java:
import java.beans.PropertyVetoException;
import javax.inject.Inject;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.querydsl.sql.PostgreSQLTemplates;
import com.querydsl.sql.SQLQueryFactory;
#Configuration
#EnableTransactionManagement
#ComponentScan("com.bonkeybee")
public class ApplicationConfiguration {
#Bean
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(JDBC_DRIVER);
comboPooledDataSource.setJdbcUrl(JDBC_URL);
comboPooledDataSource.setUser(USER);
comboPooledDataSource.setPassword(PASSWORD);
comboPooledDataSource.setMinPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setInitialPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setMaxPoolSize(MAX_POOL_SIZE);
return comboPooledDataSource;
}
#Bean
#Inject
public PlatformTransactionManager getPlatformTransactionManager(final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean
public com.querydsl.sql.Configuration getQueryDslConfiguration() {
return new com.querydsl.sql.Configuration(PostgreSQLTemplates.builder().build());
}
#Bean
#Inject
public SQLQueryFactory getSQLQueryFactory(final com.querydsl.sql.Configuration configuration, final DataSource dataSource) {
return new SQLQueryFactory(configuration, dataSource);
}
}
When Main calls catService.createCat() the cat and toy are created, then a RuntimeException is thrown as expected, however inspection of the tables afterward show the new cat and new toy created instead of being rolled back. Please SO, help me ensure no cat goes toyless >:3
EDIT: Adding imports as requested

Solved it after more searching, there were two configuration issues.
First: the transaction manager bean spring looks for by default should be named "transactionManager" otherwise you have to explicitly set the name.
Second: I added a dependency on "querydsl-sql-spring" artifact and changed my SQLQueryFactory to use a SpringConnectionProvider instead of the DataSource bean (found from this example from the querydsl people). Below is the final configuration:
#Configuration
#EnableTransactionManagement
#ComponentScan("com.bonkeybee")
public class ApplicationConfiguration {
#Bean
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(JDBC_DRIVER);
comboPooledDataSource.setJdbcUrl(JDBC_URL);
comboPooledDataSource.setUser(USER);
comboPooledDataSource.setPassword(PASSWORD);
comboPooledDataSource.setMinPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setInitialPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setMaxPoolSize(MAX_POOL_SIZE);
return comboPooledDataSource;
}
#Inject
#Bean(name = "transactionManager")
public PlatformTransactionManager getPlatformTransactionManager(final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean
public com.querydsl.sql.Configuration getQueryDslConfiguration() {
return new com.querydsl.sql.Configuration(PostgreSQLTemplates.builder().build());
}
#Inject
#Bean
public SQLQueryFactory getSQLQueryFactory(final com.querydsl.sql.Configuration configuration, final DataSource dataSource) {
Provider<Connection> provider = new SpringConnectionProvider(dataSource);
return new SQLQueryFactory(configuration, provider);
}
}
Thanks querydsl people for such a cool lib.

Since it is more than one database request involve in your transaction, you have to specify
the persistence context as PersistenceContextType.EXTENDED, which means that it can survive multiple requests.

You have to have a entity manager and then get transaction object from it.
After getting the transactionmanager, begin a new transaction, do all your database operations and then commit. Here is a sample below
EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager (PersistenceContextType.EXTENDED);
Magazine mag1 = em.find (Magazine.class, magId);
Magazine mag2 = em.find (Magazine.class, magId);
em.getTransaction().begin();
:
:
em.getTransaction().end();

Related

Liferay Kafka integration

Over internet I didn't got reference to implement Kafka in liferay.
Below are the requirements needs to be implemented
Push the message to Kafka topic
Poll and receive message from Kafka topic.
Tried below, but unable to receive message from kafka after pushed from kafka terminal
Dependencies :
compileInclude "org.springframework.kafka:spring-kafka:2.9.2"
compileInclude "org.apache.kafka:kafka-streams:3.3.1"
Code:
import org.apache.kafka.common.serialization.Serdes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.annotation.EnableKafkaStreams;
import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration;
import org.springframework.kafka.config.KafkaStreamsConfiguration;
import java.util.HashMap;
import java.util.Map;
import static org.apache.kafka.streams.StreamsConfig.APPLICATION_ID_CONFIG;
import static org.apache.kafka.streams.StreamsConfig.BOOTSTRAP_SERVERS_CONFIG;
import static org.apache.kafka.streams.StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG;
import static org.apache.kafka.streams.StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG;
#Configuration
#EnableKafka
#EnableKafkaStreams
public class KafkaConfig {
#Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME)
KafkaStreamsConfiguration kStreamsConfig() {
Map<String, Object> props = new HashMap<>();
props.put(APPLICATION_ID_CONFIG, "streams-app");
props.put(BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
props.put(DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
return new KafkaStreamsConfiguration(props);
}
}
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import org.osgi.service.component.annotations.Component;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;
#Component(immediate = true)
public class KafkaMessageReceiver {
public static Log _log = LogFactoryUtil.getLog(KafkaMessageReceiver.class);
#Async
#KafkaListener(
topics = "liferay-topic",
concurrency = "2"
)
#Transactional
public void handleMessage(String payload) {
_log.info(payload);
}
}

I want to read YAML in the map form. How can I do it?

Sample yaml looks like
"mappings":
"name": "foo"
"aliases": "abc"
Trying to implement it using PropertySourceFactory, but unsuccessful.
import import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#Configuration
//#ConfigurationProperties
#PropertySource(value = "classpath:order_config.yml", factory = YamlPropertySourceFactory.class)
public class ValidatorConfig {
#Value("${yaml.mappings}")
private Map<String, String> mappings = new HashMap<>();
#Value("${yaml.mappings.name}")
private String create;
public String getValidatorBean(String tenant, String requestType) {
System.out.println(mappings);
return "yes";
}
}
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
import java.util.Properties;
public class YamlPropertySourceFactory implements PropertySourceFactory {
#Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
}
Have tried using a bunch of methods using #Value, #ConfigurationProperties, but unsuccessful
Can we implement it using YamlMapFactoryBean. Have not been able to find its working demonstration.

java.lang.NoSuchMethodErrror:'com.mongodb.connection.ConnectionPoolSettings$Builder

I'm trying to use flapdoodle embedded mongodb for writing the unit tests. But I was receiving the following error. "java.lang.NoSuchMethodErrror:'com.mongodb.connection.ConnectionPoolSettings$Builder
com.mongodb.connection.ConnectionPoolSettings$Builder.maxWaitQueueSize(int)"
Is there any dependency I need to add here ? Is the code which I have written in #Before block correct. At the end I need MongoClient and MongoDatabse to pass to other method and test.
**MongoDBConfig file:**
import java.io.IOException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
#EnableMongoRepositories
public class MongoDBConfig {
#Value("${mongo.db.url}")
private String MONGO_DB_URL;
#Value(("${mongo.db.port:27017}"))
private int MONGO_DB_PORT;
#Value("${mongo.db.name}")
private String MONGO_DB_NAME;
#Bean
public MongoTemplate mongoTemplate() throws IOException {
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
MongoTemplate mongoTemplate = new MongoTemplate(mongoClient, "test");
return mongoTemplate;
}
}
**UnitTestFile:**
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import org.json.simple.parser.ParseException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.sap.crm.ana.gatewayservice.AnaGatewayServiceApplication;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.IMongodConfig;
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
#SpringBootTest
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { MongoDBConfig.class })
#TestPropertySource(locations = "classpath:application-test.properties")
public class CSNHandlerTestEmbeddedMongoDB {
private CSNHandler handler;
private MongoClient mongoClient;
private MongoDatabase database;
private String model;
private MongodExecutable mongodExecutable;
private MongoTemplate mongoTemplate;
#Before
public void setup() throws Exception {
MongodStarter starter = MongodStarter.getDefaultInstance();
String bindIp = "localhost";
int port = 27017;
IMongodConfig mongodConfig = new MongodConfigBuilder().version(Version.Main.PRODUCTION)
.net(new Net(bindIp, port, Network.localhostIsIPv6())).build();
this.mongoClient = new MongoClient(bindIp, port);
this.database = mongoClient.getDatabase("test");
mongodExecutable = null;
try {
mongodExecutable = starter.prepare(mongodConfig);
mongodExecutable.start();
} catch (Exception e) {
// log exception here
if (mongodExecutable != null)
mongodExecutable.stop();
}
}
#Test
public void testCSNHandler() throws IOException, ParseException {
handler = new CSNHandler(database);
handler.insertUpdateAnaModel("100", model);
}
#After
public void teardown() throws Exception {
if (mongodExecutable != null)
mongodExecutable.stop();
}
}
**Dependencies:**
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.9</version>
</dependency>

how to mock new SimpleJdbcCall

Can you please help me to mock SimpleJdbcCall?
the actual class to test is below.
import java.sql.Types;
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class HeartBeat {
private static final Logger LOGGER = LogManager.getLogger(HeartBeat.class);
#Autowired
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall jdbcCall;
#PostConstruct
private void applicationStarted() {
LOGGER.info("Application has Started.");
DBCall();
}
#Scheduled(fixedRateString="${application.heartbeatInterval}")
public void sendHeartbeat() {
DBCall();
}
private void DBCall() {
if ( this.jdbcTemplate == null ) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
jdbcTemplate.setResultsMapCaseInsensitive(true);
jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName("schema")
.withCatalogName("catalogName")
.withProcedureName("cleanup");
jdbcCall.execute(new HashMap<String, Object>(0));
jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName("schema")
.withCatalogName("catalogName")
.withProcedureName("register")
.declareParameters(new SqlParameter("id", Types.VARCHAR))
.declareParameters(new SqlParameter("name", Types.VARCHAR));
MapSqlParameterSource paramMap = new MapSqlParameterSource().addValue("id", "abc").addValue("name", "def");
jdbcCall.execute(paramMap);
}
}
to test out above code, I've created
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import java.util.HashMap;
import java.util.Map;
public class HeartBeatTest {
HeartBeat heartBeat;
private JdbcTemplate mockedJdbcTemplate;
private SimpleJdbcCall mockedJdbcCall;
private Map<String, Object> result;
#Before
public void setUp() throws Exception {
this.heartBeatComponent = new HeartBeatComponent();
result = new HashMap<String, Object>();
mockedJdbcTemplate = Mockito.mock(JdbcTemplate.class);
mockedJdbcCall = Mockito.mock(SimpleJdbcCall.class);
Whitebox.setInternalState(heartBeatComponent, "jdbcTemplate",mockedJdbcTemplate);
Whitebox.setInternalState(heartBeatComponent, "jdbcCall",mockedJdbcCall);
// section1
//PowerMockito.whenNew(SimpleJdbcCall.class).withArguments(mockedJdbcTemplate).thenReturn(mockedJdbcCall);
// section2
PowerMockito.whenNew(SimpleJdbcCall.class).withAnyArguments().thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withSchemaName(any(String.class))).thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withCatalogName(any(String.class))).thenReturn(mockedJdbcCall);
Mockito.when(mockedJdbcCall.withProcedureName(any(String.class))).thenReturn(mockedJdbcCall);
}
#Test
public void sendHeartbeatTest() {
Mockito.when(mockedJdbcCall.execute(anyMap())).thenReturn(result);
Mockito.when(mockedJdbcCall.execute(any(MapSqlParameterSource.class))).thenReturn(result);
heartBeat.sendHeartbeat();
Mockito.verify(mockedJdbcCall, Mockito.times(1)).execute(anyMap());
Mockito.verify(mockedJdbcCall, Mockito.times(1)).execute(any(MapSqlParameterSource.class));
}
}
but it does not work as expected. what I can see from debug mode,
jdbcCall got mockedJdbcCall but because of new SimpleJdbcCall() along with .withSchemaName and others, it got overwritten by simpleJdbcCall. My expectation was when new SimpleJdbcCall being called it returns mockedJdbcCall that I set up PowerMockito.whenNew...
I've tried section 1 and section 2 for PowerMockito.whenNew
Did I misunderstand PowerMockito.whenNew? or missed anything from the code?
Please, guide me.
You need to tell PowerMock that you want to mock construction of the SimpleJdbcCall class inside the HeartBeat class. Try adding the following annotations to your test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(HeartBeat.class)
public class HeartBeatTest {
...
}
Reference: how-to-mock-construction-of-new-objects

#Autowired get null value

In Login class #Autowired is not null but when I try to use postman call Logout class #Autowired get null. I copy code from Login to Logout class just change variable name all code is same pattern I don't know what happening
package xxx.api.login
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import xxx.api.domain.logout.LoginRequest;
import xxx.api.domain.logout.LoginResponse;
import xxx.converter.FieldValidation;
import xxx.dto.log.MessageLog;
import xxx.logging.LogFactory;
#Component
public class LoginClient {
#Autowired
FieldValidation fieldValidation;
public LoginResponse login(LoginRequest loginRequest) throws Exception {
ObjectMapper mapper = new ObjectMapper();
final String url = "http://localhost:xxx/xxx/login";
LoginResponse responseObject = null;
try {
String requestData = mapper.writeValueAsString(loginRequest);
responseObject = login(url, requestData);
fieldValidation.validateResponse(responseObject, "login");
// 'fieldValidation' not null
This is my Login class. Return result as I expect.
package xxx.api.logout;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import xxx.api.domain.logout.LogoutRequest;
import xxx.api.domain.logout.LogoutResponse;
import xxx.converter.FieldValidation;
import xxx.dto.log.MessageLog;
import xxx.logging.LogFactory;
#Component
public class LogoutClient {
#Autowired
FieldValidation fieldValidation;
public LogoutResponse logout(LogoutRequest logoutRequest) throws Exception {
ObjectMapper mapper = new ObjectMapper();
final String url = "http://localhost:xxx/xxx/logout";
LogoutResponse responseObject = null;
try {
String requestData = mapper.writeValueAsString(logoutRequest);
responseObject = logout(url, requestData);
fieldValidation.validateResponse(responseObject, "logout");
// 'fieldValidation' is null then throws nullPointerException
This is my Logout class
package xxx.api.logout;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xxx.api.domain.logout.LogoutRequest;
import xxx.api.domain.logout.LogoutResponse;
import xxx.dto.log.MessageLog;
import xxx.exception.common.ErrorException;
import xxx.api.logout.LogoutClient;
import xxx.converter.FieldValidation;
#RestController
#RequestMapping(path = "/xxx")
public class LogoutServer {
#Autowired
FieldValidation fieldValidation;
#Autowired
WSLogFactory wsLog;
#PostMapping(value = "/logout", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> logout(#RequestHeader(value = "requestId") String requestId,
#RequestBody(required = true) LogoutRequest logoutRequest) throws ErrorException, Exception {
writeLogRequest(logoutRequest, logoutRequest.getClientIP(), "Request", "/xxx/logout");
fieldValidation.validateRequest(logoutRequest, "logout");
try {
LogoutClient logoutClient = new LogoutClient();
LogoutResponse response = logoutClient.logout(logoutRequest);
return new ResponseEntity<LogoutResponse>(response, HttpStatus.OK);
} catch (Exception e) {
throw e;
}
}
This is Logout Controller
#org.springframework.context.annotation.Configuration
#PropertySource("file:${layout.properties_file}")
public class FieldValidation {
// do somethings
}
This is my FieldValidation class.
{
"timestamp": 1550490230074,
"status": 500,
"error": "Internal Server Error",
"exception": "java.lang.NullPointerException",
"message": "No message available",
"path": "/umm/logout"
}
This is return when I call my Logout class.
This is my project structure
xxx.api.login <<< LoginClient.java
xxx.api.logout <<< LogoutClient.java
xxx.converter <<< FieldValidation.java
This is my main program
package xxx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I try to replace #Component to #Configuration but still doesn't works.
I don't need 'fieldValidation' in Logout class or another class be a null value.
package xxx.converter;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Year;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.format.ResolverStyle;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import org.springframework.context.annotation.Configuration;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.validator.routines.BigDecimalValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import com.fasterxml.jackson.databind.ObjectMapper;
import xxx.exception.common.ErrorException;
#Configuration
#PropertySource("file:${layout.properties_file}")
public class FieldValidation {
public void validateObject(Object objResponse, String config) throws Exception {
try {
List<Configuration> confs = objectMapper.readValue(config,
objectMapper.getTypeFactory().constructCollectionType(List.class, Configuration.class));
for (int i = 0; i < confs.size(); i++) {
Configuration configuration = confs.get(i);
Object objValue = getValue(configuration.getFieldName(), objResponse);
Validation validation = new Validation();
BeanUtils.copyProperties(validation, configuration);
isValid(objValue, validation);
if (configuration.getType().equalsIgnoreCase("object")) {
List<Validation> validations = configuration.getValidation();
Class<?> act = Class.forName(configuration.getClassName());
Object objectConfig = act.cast(objValue);
validateObject(objectConfig, validations);
}
}
} catch (Exception e) {
throw e;
}
}
This is full import of FieldValidation class and replace #Configuration and I get this error.
configuration.getFieldName() << error The method is undefined for type Configuration
configuration.getType() << error The method is undefined for type Configuration
configuration.getValidation() << error The method is undefined for type Configuration
configuration.getClassName() << error The method is undefined for type Configuration

Categories