Cannot resolve JacksonTableTransformer for Cucumber 4.x.x - datatable

Following this example, I am converting Cucumber 3.x.x datatable configurer to Cucumber 4.2.0 using JacksonTableTransformer but is saying it cannot be resolved to a type.
Feature
And I Enter My Regular Income Sources
| name | Salary |
| amount | 25000 |
| frequency | every 2 weeks |
And I Enter My Regular Expenses
| name | amount | frequency |
| Electricity | 5500 | Monthly |
| Water | 900 | Weekly |
| Internet | 1900 | Every 2 Weeks |
| Cable TV | 555 | Daily |
Configurer
import io.cucumber.datatable.dependency.com.fasterxml.jackson.databind.ObjectMapper;
public class Configurer implements TypeRegistryConfigurer {
#Override
public Locale locale() {
return Locale.ENGLISH;
}
#Override
public void configureTypeRegistry(TypeRegistry registry) {
// Just added these 2 lines for Cucumber 4.2.0
JacksonTableTransformer jacksonTableTransformer = new JacksonTableTransformer();
registry.setDefaultDataTableEntryTransformer(jacksonTableTransformer);
/*
* Maps DataTable with header row to multiple objects of Type<T>. Each row below
* the header is an object.
*/
registry.defineDataTableType(new DataTableType(Transaction.class, new TableEntryTransformer<Transaction>() {
#Override
public Transaction transform(Map<String, String> entry) {
return new Transaction(entry);
}
}));
/*
* Maps DataTable with label column to a single object of Type<T>. Left column
* is field name, right column is value.
*/
registry.defineDataTableType(new DataTableType(Transaction.class, new TableTransformer<Transaction>() {
#Override
public Transaction transform(DataTable table) throws Throwable {
return new Transaction(table.asMaps().get(0));
}
}));
}
}
I only have 2 datatables and the configurer works for 3.x.x and 4.x.x if I remove the 2 lines added. I do want to use the object mapper though.

This worked but not exactly sure how. If anyone can add one-liner comments or drop an explanation it would be great for reference for everyone. Thanks!
Type
public class Transaction {
private String name = null;
private String amount = null;
private String frequency = null;
private String month = null;
public Transaction() {
// Empty constructor
}
public Transaction(Map<String, String> entry) {
this.name = entry.get("name");
this.amount = entry.get("amount");
this.frequency = entry.get("frequency");
this.month = entry.get("month");
}
// getters and setters
}
Feature
And I Enter My Regular Income Sources
| name | Salary |
| amount | 25000 |
| frequency | every 2 weeks |
And I Enter My Regular Expenses
| name | amount | frequency |
| Electricity | 5500 | Monthly |
| Water | 900 | Weekly |
| Internet | 1900 | Every 2 Weeks |
| Cable TV | 555 | Daily |
StepDef
#When("I Enter My Regular Income Sources")
public void I_Enter_My_Regular_Income_Sources(#Transpose Transaction transaction) throws Throwable {
// vertical datatable transforms to a single object
// column 1 = field name, column 2 = value
}
#When("I Enter My Regular Expenses")
public void I_Enter_My_Regular_Expenses(DataTable table) throws Throwable {
// datatable with header row transforms to a List of objects
// 1 row = 1 object
List<Transaction> transactions = table.asList(Transaction.class);
}
Configurer
public class Configurer implements TypeRegistryConfigurer {
#Override
public Locale locale() {
return Locale.ENGLISH;
}
#Override
public void configureTypeRegistry(TypeRegistry registry) {
JacksonTableTransformer jtt = new JacksonTableTransformer();
registry.setDefaultParameterTransformer(jtt);
registry.setDefaultDataTableCellTransformer(jtt);
registry.setDefaultDataTableEntryTransformer(jtt);
/*
* Maps DataTable with label column to a single object of Type<T>. Left column
* is field name, right column is value.
*/
registry.defineDataTableType(new DataTableType(Transaction.class, new TableTransformer<Transaction>() {
#Override
public Transaction transform(DataTable table) throws Throwable {
return new Transaction(table.asMaps().get(0));
}
}));
}
private static final class JacksonTableTransformer
implements ParameterByTypeTransformer, TableCellByTypeTransformer, TableEntryByTypeTransformer {
private final ObjectMapper objMapper = new ObjectMapper();
#Override
public Object transform(String fromValue, Type toValueType) throws Throwable {
return objMapper.convertValue(fromValue, objMapper.constructType(toValueType));
}
#Override
public <T> T transform(String value, Class<T> cellType) throws Throwable {
return objMapper.convertValue(value, cellType);
}
#Override
public <T> T transform(Map<String, String> entry, Class<T> type, TableCellByTypeTransformer cellTransformer)
throws Throwable {
return objMapper.convertValue(entry, type);
}
}
}

Following this example, I am converting Cucumber 3.x.x datatable configurer to Cucumber 4.2.0 using JacksonTableTransformer but is saying it cannot be resolved to a type.
If you read the full class file that you linked you'll find that JacksonTableTransformer is defined at line 99. I.e. you will have to define this class yourself.

Related

Spring Boot : mapping between entity and database not working.(Getting {} in response body)

I'm trying to create a webservice but when I try to get records from database(MariaDB), the response is being shown as {} and does not show the actual fields.The code is as below.
(Imports are hidden)
Customer.java
#AllArgsConstructor
#Data
#Entity
#Table(name ="customer")
public class Customer {
#Id
#Column(name="customer_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
Long customerId;
#Column(name = "acc_holder_name")
String accHolderName;
#Column(name = "clear_balance")
Long clearBalance;
#Column(name = "over_draft")
Boolean overDraft;
public Customer() {}
public Customer(Long id)
{
this.customerId = id;
this.accHolderName = "default";
this.clearBalance = (long) 0;
this.overDraft = false;
}
public String toString()
{
return this.customerId + this.accHolderName;
}
public Customer(String accHolderName, long clearBalance, boolean overDraft)
{
this.accHolderName = accHolderName;
this.clearBalance = clearBalance;
this.overDraft = overDraft;
}
}
CustomerService.java
#Service
public class CustomerService {
private CustomerRepository customerRepo;
#Autowired
public CustomerService(CustomerRepository cr)
{
this.customerRepo = cr;
}
public List<Customer> getCustomers(){
List<Customer> ls = customerRepo.findAll();
return ls;
}
}
CustomerController.java
#RestController
#RequestMapping("customer")
public class CustomerController {
private CustomerService custService;
#Autowired
public CustomerController(CustomerService cs)
{
this.custService = cs;
}
#GetMapping
#ResponseBody
public List<Customer> getCustomers() {
return custService.getCustomers();
}
}
application.properties
spring.datasource.url=jdbc:mariadb://localhost:3306/sample-db
spring.datasource.username=hidden
spring.datasource.password=hidden
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.hibernate.ddl-auto = update
CustomerRepostitory.java
#Repository
public interface CustomerRepository extends JpaRepository<Customer,Long> {
}
My table is follows
+-----------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+----------------+
| customer_id | int(11) | NO | PRI | NULL | auto_increment |
| acc_holder_name | varchar(40) | YES | | NULL | |
| clear_balance | int(11) | YES | | NULL | |
| over_draft | tinyint(1) | YES | | NULL | |
+-----------------+-------------+------+-----+---------+----------------+
My table has 6 records inserted. I send the following request
curl --location --request GET 'localhost:8080/customer/' \
--data-raw ''
And get the following response
[
{},
{},
{},
{},
{},
{}
]
It seems it can't serialize the JSON to the output, so you can add #JsonProperty("variable") into all variables in Customer object, like this:
public class Customer {
#Id
#Column(name="customer_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
#JsonProperty("customerId")
Long customerId;
#Column(name = "acc_holder_name")
#JsonProperty("accHolderName")
String accHolderName;
#Column(name = "clear_balance")
#JsonProperty("clearBalance")
Long clearBalance;
#Column(name = "over_draft")
#JsonProperty("overDraft")
Boolean overDraft;
// ...
}
Don’t expose your JPA entities in your Rest API. It is a bad practice. Exposing your entities creates a strong coupling between your API and your persistence model.
Therefore use DTO(Data Transfer Object) to return your data. you can use model mapper to map Entity to DTO as bellows.
#Data
public class CustomerDTO {
Long customerId;
String accHolderName;
Long clearBalance;
Boolean overDraft;
}
use bellow dependency to your pom.xml to get model mapper.
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.5</version>
</dependency>
then map an entity to DTO as follows.
public List<CustomerDTO> getCustomers(){
List<CustomerDTO> ls = customerRepo.findAll()
.stream()
.map(customer->
new ModelMapper().map(page, SimpleBaseDTO.class))
.collect(Collectors.toList());
return ls;
}

Vaadin8 grid with List<~> in property

I am trying to create a grid using Vaadin and having trouble in showing data which is inside the data source. The Datasource definition is like below
public class Customer {
private String name;
private List<Contacts> contacts;
}
public class Contacts {
private String phonecontact;
private String emailcontact;
}
Now when I write the code to show data using Vaadin
private Grid<Customer> grid=new Grid<>(Customer.class);
grid.setItems(createCutromers());
...............
..............
private List<Customer> createCutromers(){
List<Customer> customerList=new ArrayList<>();
Customer cust=new Customer();
cust.setName("Rocky");
Contacts cont=new Contacts();
List<Contacts> contactsList=new ArrayList();
cont.setEmailcontact("wwww");cont.setPhonecontact("212");
contactsList.add(cont);
cust.setContacts(contactsList);
customerList.add(cust);
return customerList;
}
Now I am trying to show Name and contacts in Grid , how should I go about it? The issue is List is shown as Object. What could be the easiest way to do it.
The output should be like
name | phonecontact | emailcontacts
-----------------------------------------
Rocky | 212 | www

Spring MongoTemplate insert succes or failed

How do I check if the value that is inserted into the collection using a MongoTemplate is saved successfully?
MongoTemplate template;
User user=new User();
user.name="Mark";
user.email="mark#mark.com"
template.insert(user);
Insert , save or any method in MongoTemplate does not return true or false.
It will throw an exception here is the flow of methods:
template.insert(object)
|
|
templateinsert(Object objectToSave, String collectionName)
|
|
protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer)
|
|
protected Object insertDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass)
|
|
Here is the source code for insertDBObject
protected Object insertDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass) {
if(LOGGER.isDebugEnabled()) {
LOGGER.debug("Inserting DBObject containing fields: {} in collection: {}", dbDoc.keySet(), collectionName);
}
return this.execute(collectionName, new CollectionCallback() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
MongoAction mongoAction = new MongoAction(MongoTemplate.this.writeConcern, MongoActionOperation.INSERT, collectionName, entityClass, dbDoc, (DBObject)null);
WriteConcern writeConcernToUse = MongoTemplate.this.prepareWriteConcern(mongoAction);
WriteResult writeResult = writeConcernToUse == null?collection.insert(new DBObject[]{dbDoc}):collection.insert(dbDoc, writeConcernToUse);
MongoTemplate.this.handleAnyWriteResultErrors(writeResult, dbDoc, MongoActionOperation.INSERT);
return dbDoc.get("_id");
}
});
}
which will throw exception when you write fails, They are runtime exception. Runtime excpetions are translated by MongoExceptionTranslator
.So any insert which doesn't throw any exception is successful.

RowMapper returns the list , but execute returned values returns the list size as 1?

please find below my sample code.The Row mapper returns a list. When printed it give me the size in the DB but when i check
(List) employeeDaomap .get("allEmployees") i get the list size as 1 , and entire rows as one item? why what is the wrong in implementation
Also Spring doc says not to use rs.next(), how do we get the list of
values from the DB
public class MyTestDAO extends StoredProcedure {
/** The log. */
static Logger log = Logger.getLogger(MyTestDAO.class);
private static final String SPROC_NAME = "TestSchema.PKG_Test.prc_get_employee_list";
TestRowMapper mapper=new TestRowMapper();
public MyTestDAO(DataSource dataSource){
super(dataSource, SPROC_NAME);
declareParameter(new SqlOutParameter("allEmployees", OracleTypes.CURSOR, mapper));
compile();
}
/**
* Gets the myemplist data from the DB
*
*/
public List<EmployeeDAO> getEmployeeList()
throws Exception {
Map<String,Object> employeeDaomap =new HashMap<String,Object>();
employeeDaomap =execute();
log.info("employeeDaomap after execute ="+employeeDaomap);
log.info("employeeDaomap after execute size ="+employeeDaomap.size()); // expected 1
List<EmployeeDAO> list = (List<EmployeeDAO>) employeeDaomap .get("allEmployees");
log.info("size of the list ="+list.size()); // need to get the size of the list ,
return list;
}
private Map<String, Object> execute() {
return super.execute(new HashMap<String, Object>());
}
}
public class TestRowMapper implements RowMapper<List<EmployeeDAO>> {
static Logger log = Logger.getLogger(TestRowMapper.class);
#Override
public List<EmployeeDAO> mapRow(ResultSet rs, int rowNum)
throws SQLException {
// TODO Auto-generated method stub
rs.setFetchSize(3000);
List<EmployeeDAO> responseItems = new ArrayList<EmployeeDAO>();
EmployeeDAO responseItem = null;
log.info("row num "+rowNum);
while (rs.next()) {
responseItem = new EmployeeDAO();
responseItem.setID(rs.getString("id"));
responseItem.setName(rs.getString("name"));
responseItem.setDesc(rs.getString("desc"));
responseItems.add(responseItem);
}
log.info("TestRowMapper items ="+responseItems);
return responseItems;
}
}
The solution is to use the implements ResultSetExtractor instead of RowMapper and provide implementation for extractData.
public class TestRowMapper implements ResultSetExtractor<List<EmployeeDAO>> {
static Logger log = Logger.getLogger(TestRowMapper.class);
#Override
public List<EMAccountResponse> extractData(ResultSet rs)
throws SQLException, DataAccessException {
rs.setFetchSize(3000);
List<EmployeeDAO> responseItems = new ArrayList<EmployeeDAO>();
EmployeeDAO responseItem = null;
log.info("row num "+rowNum);
while (rs.next()) {
responseItem = new EmployeeDAO();
responseItem.setID(rs.getString("id"));
responseItem.setName(rs.getString("name"));
responseItem.setDesc(rs.getString("desc"));
responseItems.add(responseItem);
}
log.info("TestRowMapper items ="+responseItems);
return responseItems;
}
}

Dynamic search by criteria

I am using QueryDSL with Spring Data Jpa and i want execute some dynamic search.
I follow this Answer and it's okey with BooleanBuilder But in my case I have to make joins.
So how can i make it if i have 3 joins on player, player_team, team and i have optional parameters on the name of player and name of his team ?
________ ___________________ _______
| player | | player_team | | team |
|------ | |---------------- | |-------|
| id | | player_team_id (pk) | | id |
| name | | player_id (fk) | | name |
------ | team_id (fk) | -------
-----------
player.java
#Entity
#Table(...)
public class Player implements java.io.Serializable {
private Integer idPlayer ;
private String namePlayer;
private Set<PlayerTeam> player_teams = new HashSet<PlayerTeam>(0);
...
}
team.java
#Entity
#Table(...)
public class Team implements java.io.Serializable {
private Integer idTeam ;
private String nameTeam;
private Set<PlayerTeam> player_teams = new HashSet<PlayerTeam>(0);
...
}
player_team.java
#Entity
#Table(...)
public class PlayerTeam implements java.io.Serializable {
private Integer idPlayerTeam ;
private Team team;
private Player paleyr;
...
}
and for each domaine i have respository like that :
public interface PlayerRespository extends JpaRepository<Player, Integer>, QueryDslPredicateExecutor<Player> {
}
If you don't put extra properties into PlayerTeam it shouldn't be modeled as an entity. Concerning the conditions it would be
player.namePlayer.eq(...)
and
new JPASubQuery().from(playerTeam)
.where(playerTeam.player.eq(player), palyerTeam.team.name.eq(...))
.exists()
Have you tried using Specification? Spring's JPA Repositories has this method for finding results using Specifications:
List<T> findAll(Specification<T> spec);
There are different approaches for building a specification, my approach is tailored for accepting request from my REST service, so I essentially make a blank entity of a given type (Foo in this case) and set whatever search criteria was provided in the request (name for example), then I build predicates from each field (if name field is specified then add 'name equals "bob"' predicate).
Here is an example of a Specification builder:
import static org.springframework.data.jpa.domain.Specifications.where;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import com.acme.model.security.Principal;
public class FooSpecification {
private final Foo criteria;
private String query;
public FooSpecification(String query, Foo criteria) {
this.query = query;
this.criteria = criteria;
}
public Specification<Foo> trainerEquals() {
if (criteria.getTrainer() == null) {
return null;
}
return new Specification<Foo>() {
#Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.<Principal>get("trainer").<Long>get("id"), criteria.getTrainer().getId());
}
};
}
public <T> Specification<Foo> valueEquals(final T value, final String field) {
if (value == null) {
return null;
}
return new Specification<Foo>() {
#Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.<T> get(field), value);
}
};
}
/**
* Convert input string to lower case, appends '%' around it and does SQL LIKE comparison with the field value, also lower cased.
* If value is null, no comparison is done. Example:
*
* value = "John";
* field = "firstName";
*
* resulting specification = "name like '%john%'"
*
* #param value string or null
* #param field field name
* #return SQL LIKE specification for the given value or null if value is null
*/
public Specification<Foo> stringLike(final String value, final String field) {
if (StringUtils.isBlank(value)) {
return null;
}
return new Specification<Foo>() {
#Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(cb.lower(root.<String> get(field)), getLikePattern(value));
}
};
}
private String getLikePattern(String searchTerm) {
return new StringBuilder("%")
.append(searchTerm.toLowerCase().replaceAll("\\*", "%"))
.append("%")
.toString();
}
public Specification<Foo> fullSearch() {
return where(trainerEquals())
.and(valueEquals(criteria.getName(), "name"))
.and(valueEquals(criteria.getInstructions(), "description"))
.and(valueEquals(criteria.isAwesome(), "isAwesome"))
.and(
where(
stringLike(query, "name"))
.or(stringLike(query, "instructions")
)
);
}
}

Resources