Testing controllers using Spring, JUNIT, MockMvc and Hamcrest - java

I am trying to test a controller of mine which returns me a List of Objects on the get method to populate a dropdown on my page.
I am trying to write a JUnit test using MockMvc and Hamcrest to test the same.
I want to compare the List of objects and test if it fails or not.
I have created a static List of objects in my Test.java and I am getting a List of objects from the model.attribute method.
To Test: if both the List of Objects are equal and don't contain any other objects.
My object is called Option which has 3 properties. Key, Value and Selected. I have to check if the all the keys exists in the List or not.
I am unable to create a matcher to do the same. I am trying to create a matcher to compare my List.
So far I have done the following:
#Before
public void setup() throws Exception {
// This would build a MockMvc with only the following controller
this.mockMvc = MockMvcBuilders.standaloneSetup(openAccountController)
.build();
}
#Test
public void testOpenAccount() {
try {
setAllLegislations();
this.mockMvc
.perform(get("/open_account.htm"))
// This method is used to print out the actual httprequest
// and httpresponse on the console.
.andDo(print())
// Checking if status is 200
.andExpect(status().isOk())
.andExpect(
model().attributeExists("appFormAccountPlans",
"appFormLiraLegislations",
"appFormLrspLegislations",
"appFormRlspLegislations"))
.andExpect(
model().attribute("appFormAccountPlans", hasSize(5)))
.andExpect(
model().attribute("appFormLiraLegislations",
hasSize(8)))
.andExpect(
model().attribute("appFormLrspLegislations",
hasSize(2)))
.andExpect(
model().attribute("appFormRlspLegislations",
hasSize(1)))
.andExpect(
model().attribute(
"appFormLiraLegislations",
hasKeyFeatureMatcher(getLiraLegislations(allLegislations))));
private Matcher<List<Option>> hasKeyFeatureMatcher(
final List<Option> expectedOptions) {
return new FeatureMatcher<List<Option>, List<Option>>(
equalTo(expectedOptions), "Options are", "was") {
#Override
protected List<Option> featureValueOf(List<Option> actualOptions) {
boolean flag = false;
if (actualOptions.size() == expectedOptions.size()) {
for (Option expectedOption : expectedOptions) {
for (Option actualOption : actualOptions) {
if (expectedOption.getKey().equals(
actualOption.getKey())) {
flag = true;
} else {
flag = false;
break;
}
}
}
}
if (flag)
return actualOptions;
else
return null;
}
};
}
private List<Option> getLiraLegislations(List<Option> legislation) {
List<Option> liraLegislations = new ArrayList<Option>();
Iterator<Option> iterator = legislation.iterator();
while (iterator.hasNext()) {
Option option = iterator.next();
if (LIRA_LEGISLATIONS.contains(option.getKey())) {
liraLegislations.add(option);
}
}
return liraLegislations;
}
private List<Option> allLegislations;
public List<Option> getAllLegislations() {
return allLegislations;
}
public void setAllLegislations() {
allLegislations = new ArrayList<Option>();
for (String key : ALL_LEGISLATIONS) {
Option option = new Option();
option.setKey(key);
allLegislations.add(option);
}
}
private static final Set<String> ALL_LEGISLATIONS = new HashSet<String>(
Arrays.asList(AccountLegislationEnum.AB.toString(),
AccountLegislationEnum.MB.toString(),
AccountLegislationEnum.NB.toString(),
AccountLegislationEnum.NL.toString(),
AccountLegislationEnum.NS.toString(),
AccountLegislationEnum.ON.toString(),
AccountLegislationEnum.QC.toString(),
AccountLegislationEnum.SK.toString(),
AccountLegislationEnum.BC.toString(),
AccountLegislationEnum.FE.toString(),
AccountLegislationEnum.NT.toString(),
AccountLegislationEnum.PE.toString(),
AccountLegislationEnum.YT.toString(),
AccountLegislationEnum.NU.toString(),
AccountLegislationEnum.UNKNOWN.toString()));
This is how I am getting my model attribute as:
Attribute = appFormLiraLegislations
value = [com.abc.arch.core.gui.eform.gui.Option#199d1739, com.abc.arch.core.gui.eform.gui.Option#185fac52, com.abc.arch.core.gui.eform.gui.Option#312a47fe, com.abc.arch.core.gui.eform.gui.Option#4edc8de9, com.abc.arch.core.gui.eform.gui.Option#71e8e471, com.abc.arch.core.gui.eform.gui.Option#70edf123, com.abc.arch.core.gui.eform.gui.Option#15726ac1, com.abc.arch.core.gui.eform.gui.Option#abeafe7]
Thanks in advance.

You can make your life definitely easier when you correctly implement Option object hashCode() and equals() methods using key attribute; then you can simply write:
model().attribute("appFormLiraLegislations",getLiraLegislations(allLegislations)))
and rely on list1.equals(list2) method to do the work for you.
Option hashCode and equals implementation:
public class Option {
private String key;
private String label;
...
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Option other = (Option) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
}
Methods above are generated by my IDE. I also don't know exactly what is structure of your Option class, so I add label property for example in addition to key property.

I created a custom Hamcrest matcher to compare the List of Option by checking the size and the keys.
private Matcher<List<Option>> hasOptionsFeatureMatcher(
final List<Option> expectedOptions) {
return new FeatureMatcher<List<Option>, List<Option>>(
equalTo(expectedOptions), "Options are", "Options were") {
#Override
protected List<Option> featureValueOf(List<Option> actualOptions) {
boolean flag = false;
if (expectedOptions.size() == actualOptions.size()) {
for (Option expected : expectedOptions) {
for (Option actual : actualOptions) {
if (expected.getKey().equals(actual.getKey())) {
flag = true;
break;
} else {
flag = false;
}
}
}
} else
flag = false;
if (flag)
return expectedOptions;
else
return null;
}
};
Implementation would be as follows:
private static final ImmutableBiMap<String, String> LIRA = new ImmutableBiMap.Builder<String, String>()
.put(AccountLegislationEnum.AB.toString(), "ALBERTA")
.put(AccountLegislationEnum.MB.toString(), "MANITTOBA")
.put(AccountLegislationEnum.NB.toString(), "NEW BRUNSWICK")
.put(AccountLegislationEnum.NL.toString(), "NEWFOUNDLAND")
.put(AccountLegislationEnum.NS.toString(), "NOVA SCOTIA")
.put(AccountLegislationEnum.ON.toString(), "ONTARIO")
.put(AccountLegislationEnum.QC.toString(), "QUEBEC")
.put(AccountLegislationEnum.SK.toString(), "SASKATCHEWAN")
.put(AccountLegislationEnum.UNKNOWN.toString(), "UNKNOWN").build();
private List<Option> prepareOptions(ImmutableBiMap<String, String> map) {
List<Option> legislations = new ArrayList<Option>();
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
Option option = new Option();
option.setKey(key);
option.setValue(value);
legislations.add(option);
}
return legislations;
}
.andExpect(model().attribute("appFormLiraLegislations",hasOptionsFeatureMatcher(prepareOptions(LIRA))))

Related

How to configurate mapstruct to ignore map object when all field are null

env:
jdk: 17.0.1
mapstruct: 1.5.1.Final
Using the default configuration I generated the following code
protected AgentInfo wealthProdAccountInfoDTOToAgentInfo(WealthProdAccountInfoDTO wealthProdAccountInfoDTO) {
if ( wealthProdAccountInfoDTO == null ) {
return null;
}
String agentName = null;
String agentIdentityType = null;
String agentIdentityNo = null;
String agentIdentityExpireAt = null;
agentName = wealthProdAccountInfoDTO.getAgentName();
agentIdentityType = wealthProdAccountInfoDTO.getAgentIdentityType();
agentIdentityNo = wealthProdAccountInfoDTO.getAgentIdentityNo();
agentIdentityExpireAt = wealthProdAccountInfoDTO.getAgentIdentityExpireAt();
AgentInfo agentInfo = new AgentInfo( agentName, agentIdentityType, agentIdentityNo, agentIdentityExpireAt );
return agentInfo;
}
But I want to return null when all field of source are null, like this
protected AgentInfo wealthProdAccountInfoDTOToAgentInfo(WealthProdAccountInfoDTO wealthProdAccountInfoDTO) {
if ( wealthProdAccountInfoDTO == null ) {
return null;
}
// add check logic
if (agentName == null && agentIdentityType == null && agentIdentityNo == null && agentIdentityExpireAt == null) {
return null;
}
String agentName = null;
String agentIdentityType = null;
String agentIdentityNo = null;
String agentIdentityExpireAt = null;
agentName = wealthProdAccountInfoDTO.getAgentName();
agentIdentityType = wealthProdAccountInfoDTO.getAgentIdentityType();
agentIdentityNo = wealthProdAccountInfoDTO.getAgentIdentityNo();
agentIdentityExpireAt = wealthProdAccountInfoDTO.getAgentIdentityExpireAt();
AgentInfo agentInfo = new AgentInfo( agentName, agentIdentityType, agentIdentityNo, agentIdentityExpireAt );
return agentInfo;
}
how should I configure it?
Unfortunately there's no clean solution for your problem, except implementing code for null check by yourself, Marc specified the right approach to your problem (I'd go with it personally or would use default method for the same purpose).
I can add some workarounds, which will only work if mapping target is inner object:
Use #BeforeMapping to set input inner object to null, so when there will be null-check it will be skipped
#BeforeMapping
default void clearData(TestB source, #MappingTarget TestA target) {
TestD innerD = source.getInnerD();
if (innerD.getSecond() == null && innerD.getFirst() == null) {
source.setInnerD(null);
}
}
And it will generate the following code:
#Override
public TestA from(TestB input) {
....
clearData( input, testA ); //set input field to null
testA.setInnerC( fromInner( input.getInnerD() ) );
....
}
#Override
public TestC fromInner(TestD input) {
if ( input == null ) { //skip because of null
return null;
}
....
}
Use #AfterMapper to set output parameter to null(it will be mapped in the first place, so there will be some overhead)
#AfterMapping
default void clearData(TestB source, #MappingTarget TestA target) {
TestD innerD = source.getInnerD();
if (innerD.getSecond() == null && innerD.getFirst() == null) {
target.setInnerC(null);
}
}
And generated code will be:
#Override
public TestA from(TestB input) {
....
testA.setInnerC( fromInner( input.getInnerD() ) ); //field is actually mapped but cleared later
clearData( input, testA );
return testA;
}
As I said, these solutions aren't really clean and should be seen as workarounds only. Pros of these workaround is that you will keep working with autogenerated code and these hacks will be hidden inside that code.
UPD Stumbled upon #DecoratedWith lately and it also can do the trick. https://mapstruct.org/documentation/stable/reference/html/#_customizing_mappings
Just implement decorator for iterable2iterable mapping method: List<A> from(List<b> b) and just manually iterate over b checking if all b's fields are null and if so skip it
brute force... it's a simple class, so create a custom mapper
#Mapper
public interface AgentInfoMapper {
#Named("AgentInfoNullIfContentsNull")
public static AgentInfo custom(WealthProdAccountInfoDTO dto) {
if ( wealthProdAccountInfoDTO == null ) {
return null;
}
if (agentName == null && agentIdentityType == null && agentIdentityNo == null && agentIdentityExpireAt == null) {
return null;
}
// mapping code
}
}
https://www.baeldung.com/mapstruct-custom-mapper
Thanks to ArtemAgaev's idea, I ended up considering using #AfterMapping and java reflection for this type of scenario
#AfterMapping
default void cleanData(#MappingTarget AccountInfoDomain domain) {
Optional.ofNullable(domain).ifPresent(c -> {
if (isAllFieldNull(domain.getAgentInfo())) {
domain.setAgentInfo(null);
}
});
}
public static boolean isAllFieldNull(Object o) {
Object[] fieldsValue = getFieldsValue(o);
return Optional.ofNullable(fieldsValue).map(f -> Arrays.stream(f).allMatch(Objects::isNull)).orElse(true);
}
public static Object[] getFieldsValue(Object obj) {
if (null != obj) {
final Field[] fields = getFields(obj instanceof Class ? (Class<?>) obj : obj.getClass());
if (null != fields) {
final Object[] values = new Object[fields.length];
for (int i = 0; i < fields.length; i++) {
values[i] = getFieldValue(obj, fields[i]);
}
return values;
}
}
return null;
}

Why does this REST-service not return while the other does?

SITUATION
In the code below you can see 2 REST services which both should return a MessageVO. The first service (serviceThatDoesWork) returns a MessageVO as excpected, but the second service (serviceThatDoesNotWork) refuses to, it doesn't even give any output at all.
However returning a Response (java.ws.rs.core.Response) with serviceThatDoesNotWork does give an output. Even when I skip the 'doStuff'-methods and create a dummy-MessageVO that is exactly the same for each service, the 2nd one doesn't return anything.
QUESTION
Why does the 2nd service fail to return a MessageVO? It doens't return anything when I try returning a MessageVO, and nothing out of the ordinary appears in the logging.
The two services need to return exactly the same kind of thing but still one of them doesn't want to return anything, what am I not seeing here?
Could it be because of the path (and/or the amount of parameters)?
CODE
MyServices.java:
#Path("/myService")
...
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/myPath/{param1}/{param2}/{param3}")
public MessageVO serviceThatDoesWork(#PathParam("param1") Integer param1_id, #PathParam("param2") Integer param2_id, #PathParam("param2") Integer param2_id)
{
List<SomethingVO> lstO = MyRestServiceBusiness.doStuff(param1_id, param2_id, param3_id);
//return SUCCESS or FAIL message
MessageVO msg = new MessageVO();
if(lstO.size() > 0)
{
List<String> s = new ArrayList<String>();
for(SomethingVO k : lstO)
{
s.add(k.getId().toString());
}
msg.setItem_ids(s);
msg.setMsg("SUCCESS");
}
else
{
msg.setMsg("FAIL");
}
return msg;
}
...
#GET
#Path("/myPath/{param1}/{param2}/{param3}/{param4}/.../{param15}{a:(/a/[^/]+?)?}{b:(/b/[^/]+?)?}")
public Response serviceThatDoesNotWork(#PathParam("param1")Integer param1_id, ..., #PathParam("param15") Integer param15_id,
#PathParam("a") String a_id, #PathParam("b") String b_id)
{
//PUT 'OPTIONAL' PARAMS IN A LIST
List<Integer> lstI = new ArrayList<Integer>();
String aId = a_id != null ? a_id.split("/")[2] : null;
String bId = b_id != null ? b_id.split("/")[2] : null;
if(aId != null)
{
lstI.add(Integer.parseInt(aId ));
}
if(bId != null)
{
lstI.add(Integer.parseInt(bId ));
}
//DO STUFF
String afsId = "";
if(lstI.size() > 0)
{
afsId = MyRestServiceBusiness.doStuff(param1, ..., lstI);
}
//return SUCCESS or FAIL message
MessageVO msg = new MessageVO();
if(afsId != null && !afsId.isEmpty())
{
List<String> s = new ArrayList<String>();
s.add(afsId);
msg.setItem_ids(s);
msg.setMsg("SUCCESS");
}
else
{
List<String> s = new ArrayList<String>();
for(Integer i : lstI)
{
s.add(i.toString());
}
msg.setItem_ids(s);
msg.setMsg("FAIL");
}
//WENT THROUGH ALL ABOVE CODE AS EXPECTED, MESSAGEVO HAS BEEN FILLED PROPERLY
return msg;
}
CODE MessageVO.java:
#XmlRootElement
public class MessageVO
{
private String msg;
private List<String> item_ids;
//GETTERS
#XmlElement(name = "Message")
public String getMsg() {
return msg;
}
#XmlElement(name = "Item ID's")
public List<String> getItem_ids() {
return item_ids;
}
//SETTERS
public void setMsg(String msg) {
this.msg = msg;
}
public void setItem_ids(List<String> item_ids) {
this.item_ids = item_ids;
}
If I need to provide extra information please ask, this is my first attempt at (REST-) services.
As Vaseph mentioned in a comment I just forgot the #Produces annotation in the 2nd service.

Hibernate gives a strange ClassCast exception (using Transformers)

This code:
#Override
public List<FactCodeDto> getAllFactsWithoutParentsAsFactDto() {
String completeQuery = FactCodeQueries.SELECT_DTO_FROM_FACT_WITH_NO_PARENTS;
Query query = createHibernateQueryForUnmappedTypeFactDto(completeQuery);
List<FactCodeDto> factDtoList = query.list(); //line 133
return factDtoList;
}
calling this method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
gives me a ClassCastException -> part of the trace:
Caused by: java.lang.ClassCastException: org.bamboomy.cjr.dto.FactCodeDto cannot be cast to java.util.Map
at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102)
at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:78)
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:75)
at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:435)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
at org.hibernate.loader.Loader.list(Loader.java:2418)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:336)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1898)
at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:318)
at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:125)
at org.bamboomy.cjr.dao.factcode.FactCodeDAOImpl.getAllFactsWithoutParentsAsFactDto(FactCodeDAOImpl.java:133)
Which is pretty strange because, indeed, if you look up the source code of Hibernate it tries to do this:
#Override
#SuppressWarnings("unchecked")
public void set(Object target, Object value, SessionFactoryImplementor factory) {
( (Map) target ).put( propertyName, value ); //line 102
}
Which doesn't make any sense...
target is of type Class and this code tries to cast it to Map,
why does it try to do that???
any pointers are more than welcome...
I'm using Hibernate 5 (and am upgrading from 3)...
edit: I also use Spring (4.2.1.RELEASE; also upgrading) which calls these methods upon deploy, any debugging pointers are most welcome as well...
edit 2: (the whole FactCodeDto class, as requested)
package org.bamboomy.cjr.dto;
import org.bamboomy.cjr.model.FactCode;
import org.bamboomy.cjr.model.FactCodeType;
import org.bamboomy.cjr.utility.FullDateUtil;
import org.bamboomy.cjr.utility.Locales;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.util.Assert;
import java.util.*;
#Getter
#Setter
#ToString
public class FactCodeDto extends TreeNodeValue {
private String cdFact;
private String cdFactSuffix;
private Boolean isSupplementCode;
private Boolean isTitleCode;
private Boolean mustBeFollowed;
private Date activeFrom;
private Date activeTo;
private Boolean isCode;
private Long idFact;
private Long idParent;
private String type;
Map<Locale, String> description = new HashMap<Locale, String>(3);
public FactCodeDto() {
}
public FactCodeDto(String prefix, String suffix) {
super();
this.cdFact = prefix;
this.cdFactSuffix = suffix;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed, Long idFact, Long idParent, Boolean isCode, Boolean isTitleCode, Date from, Date to, Map<Locale, String> descriptions,String type) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
this.idFact = idFact;
this.idParent = idParent;
this.isCode = isCode;
this.isTitleCode = isTitleCode;
this.activeFrom = from;
this.activeTo = to;
if (descriptions != null) {
this.description = descriptions;
}
this.type = type;
}
public FactCodeDto(FactCode fc) {
this(fc.getPrefix(), fc.getSuffix(), fc.isSupplementCode(), fc.isHasMandatorySupplCodes(), fc.getId(), fc.getParent(), fc.isActualCode(), fc.isTitleCode(), fc.getActiveFrom(), fc.getActiveTo(), fc.getAllDesc(),fc.getType().getCode());
}
public String formatCode() {
return FactCode.formatCode(cdFact, cdFactSuffix);
}
public boolean isActive() {
Date now = new Date(System.currentTimeMillis());
return FullDateUtil.isBetweenDates(now, this.activeFrom, this.activeTo);
}
public void setDescFr(String s) {
description.put(Locales.FRENCH, s);
}
public void setDescNl(String s) {
description.put(Locales.DUTCH, s);
}
public void setDescDe(String s) {
description.put(Locales.GERMAN, s);
}
/**
* public String toString() {
* StringBuilder sb = new StringBuilder();
* sb.append(getIdFact() + ": ")
* .append(getIdParent() + ": ")
* .append(" " + cdFact + cdFactSuffix + ": " + (isSupplementCode ? "NO Principal " : " Principal "))
* .append((mustBeFollowed ? " Must Be Followed " : "NOT Must Be Followed "));
* return sb.toString();
* }
*/
public Map<Locale, String> getDescription() {
return description;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
String fullCode = formatCode();
result = prime * result + ((fullCode == null) ? 0 : fullCode.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FactCodeDto other = (FactCodeDto) obj;
return formatCode().equals(other.formatCode());
}
#Override
public boolean isChildOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isChild = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isChild = this.getIdParent().equals(((FactCodeDto) value).getIdFact());
}
}
return isChild;
}
#Override
public boolean isBrotherOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isBrother = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isBrother = this.getIdParent().equals(((FactCodeDto) value).getIdParent());
}
}
return isBrother;
}
#Override
public boolean isParentOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isParent = false;
if (value instanceof FactCodeDto) {
isParent = this.getIdFact().equals(((FactCodeDto) value).getIdParent());
}
return isParent;
}
#Override
public int compareTo(TreeNodeValue to) {
if (to instanceof FactCodeDto) {
return formatCode().compareTo(((FactCodeDto) to).formatCode());
} else return 1;
}
public String getCode() {
return formatCode();
}
}
I found that AliasToBean has changed in Hibernate 5. For me adding getter for my field fixed the problem.
This exception occurs when the setters and getters are not mapped correctly to the column names.
Make sure you have the correct getters and setters for the query(Correct names and correct datatypes).
Read more about it here:
http://javahonk.com/java-lang-classcastexception-com-wfs-otc-datamodels-imagineexpirymodel-cannot-cast-java-util-map/
I do some investigation on this question. The problem is that Hibernate converts aliases for column names to upper case — cdFact becomesCDFACT.
Read for a more deeply explanation and workaround here:
mapping Hibernate query results to custom class?
In the end it wasn't so hard to find a solution,
I just created my own (custom) ResultTransformer and specified that in the setResultTransformer method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(new FactCodeDtoResultTransformer());
//return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
the code of the custom result transformer:
package org.bamboomy.cjr.dao.factcode;
import org.bamboomy.cjr.dto.FactCodeDto;
import java.util.Date;
import java.util.List;
/**
* Created by a162299 on 3-11-2015.
*/
public class FactCodeDtoResultTransformer implements org.hibernate.transform.ResultTransformer {
#Override
public Object transformTuple(Object[] objects, String[] strings) {
FactCodeDto result = new FactCodeDto();
for (int i = 0; i < objects.length; i++) {
setField(result, strings[i], objects[i]);
}
return result;
}
private void setField(FactCodeDto result, String string, Object object) {
if (string.equalsIgnoreCase("cdFact")) {
result.setCdFact((String) object);
} else if (string.equalsIgnoreCase("cdFactSuffix")) {
result.setCdFactSuffix((String) object);
} else if (string.equalsIgnoreCase("isSupplementCode")) {
result.setIsSupplementCode((Boolean) object);
} else if (string.equalsIgnoreCase("isTitleCode")) {
result.setIsTitleCode((Boolean) object);
} else if (string.equalsIgnoreCase("mustBeFollowed")) {
result.setMustBeFollowed((Boolean) object);
} else if (string.equalsIgnoreCase("activeFrom")) {
result.setActiveFrom((Date) object);
} else if (string.equalsIgnoreCase("activeTo")) {
result.setActiveTo((Date) object);
} else if (string.equalsIgnoreCase("descFr")) {
result.setDescFr((String) object);
} else if (string.equalsIgnoreCase("descNl")) {
result.setDescNl((String) object);
} else if (string.equalsIgnoreCase("descDe")) {
result.setDescDe((String) object);
} else if (string.equalsIgnoreCase("type")) {
result.setType((String) object);
} else if (string.equalsIgnoreCase("idFact")) {
result.setIdFact((Long) object);
} else if (string.equalsIgnoreCase("idParent")) {
result.setIdParent((Long) object);
} else if (string.equalsIgnoreCase("isCode")) {
result.setIsCode((Boolean) object);
} else {
throw new RuntimeException("unknown field");
}
}
#Override
public List transformList(List list) {
return list;
}
}
in hibernate 3 you could set Aliasses to queries but you can't do that anymore in hibernate 5 (correct me if I'm wrong) hence the aliasToBean is something you only can use when actually using aliasses; which I didn't, hence the exception.
Im my case :
=> write sql query and try to map result to Class List
=> Use "Transformers.aliasToBean"
=> get Error "cannot be cast to java.util.Map"
Solution :
=> just put \" before and after query aliases
ex:
"select first_name as \"firstName\" from test"
The problem is that Hibernate converts aliases for column names to upper case or lower case
I solved it by defining my own custom transformer as given below -
import org.hibernate.transform.BasicTransformerAdapter;
public class FluentHibernateResultTransformer extends BasicTransformerAdapter {
private static final long serialVersionUID = 6825154815776629666L;
private final Class<?> resultClass;
private NestedSetter[] setters;
public FluentHibernateResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
createCachedSetters(resultClass, aliases);
Object result = ClassUtils.newInstance(resultClass);
for (int i = 0; i < aliases.length; i++) {
setters[i].set(result, tuple[i]);
}
return result;
}
private void createCachedSetters(Class<?> resultClass, String[] aliases) {
if (setters == null) {
setters = createSetters(resultClass, aliases);
}
}
private static NestedSetter[] createSetters(Class<?> resultClass, String[] aliases) {
NestedSetter[] result = new NestedSetter[aliases.length];
for (int i = 0; i < aliases.length; i++) {
result[i] = NestedSetter.create(resultClass, aliases[i]);
}
return result;
}
}
And used this way inside the repository method -
#Override
public List<WalletVO> getWalletRelatedData(WalletRequest walletRequest,
Set<String> requiredVariablesSet) throws GenericBusinessException {
String query = getWalletQuery(requiredVariablesSet);
try {
if (query != null && !query.isEmpty()) {
SQLQuery sqlQuery = mEntityManager.unwrap(Session.class).createSQLQuery(query);
return sqlQuery.setResultTransformer(new FluentHibernateResultTransformer(WalletVO.class))
.list();
}
} catch (Exception ex) {
exceptionThrower.throwDatabaseException(null, false);
}
return Collections.emptyList();
}
It worked perfectly !!!
Try putting Column names and field names both in capital letters.
This exception occurs when the class that you specified in the AliasToBeanResultTransformer does not have getter for the corresponding columns. Although the exception details from the hibernate are misleading.

How to Mock repository Items in ATG

I am trying to create a Mock class for droplet. I am able to mock the repository calls and req.getParameter but need help on how to mock the repository item list from the repository. Below is the sample code.
for (final RepositoryItem item : skuList) {
final String skuId = (String) item.getPropertyValue("id");
final String skuType = (String) item.getPropertyValue("skuType");
if (this.isLoggingDebug()) {
this.logDebug("skuType [ " + skuType + " ]");
}
final String skuActive = (String) item.getPropertyValue("isActive");
if EJSD.equalsIgnoreCase(skuType) && (skuActive.equals("1"))) {
eSkuList.add(item);
skuCode = (String) item.getPropertyValue(ESTConstants.SKU_MISC1);
} else (PJPROMIS.equalsIgnoreCase(skuType) && skuId.contains("PP") && (skuActive.equals("1"))) {
personalSkuList.add(item);
String tmp = "";
if (skuId.lastIndexOf("-") > -1) {
tmp = skuId.substring(skuId.lastIndexOf("-") + 1);
tmp = tmp.toUpperCase();
if (this.getDefaultDisplayNameMap() != null) {
String val = this.getDefaultDisplayNameMap().get(tmp);
if (StringUtils.isNotEmpty(val)) {
displayNameMap.put(skuId, val);
} else {
val = (String) item.getPropertyValue("displayName");
displayNameMap.put(skuId, val);
}
} else {
final String val = (String) item.getPropertyValue("displayName");
displayNameMap.put(skuId, val);
}
}
}
}
There are a multitude of ways to 'mock' the list. I've been doing it this was as I feel it is more readable.
#Mock private RepositoryItem skuMockA;
#Mock private RepositoryItem skuMockB;
List<RepositoryItem> skuList = new ArrayList<RepositoryItem>();
#BeforeMethod(groups = { "unit" })
public void setup() throws Exception {
testObj = new YourDropletName();
MockitoAnnotations.initMocks(this);
skuList = new ArrayList<RepositoryItem>();
skuList.add(skuMockA);
skuList.add(skuMockB);
Mockito.when(skuMockA.getPropertyValue("id")).thenReturn("skuA");
Mockito.when(skuMockA.getPropertyValue("skuType")).thenReturn(ActiveSkuDroplet.EJSD);
Mockito.when(skuMockA.getPropertyValue(ESTConstants.SKU_MISC1)).thenReturn("skuCodeA");
Mockito.when(skuMockA.getPropertyValue("displayName")).thenReturn("skuADisplayName");
Mockito.when(skuMockB.getPropertyValue("id")).thenReturn("skuB-PP");
Mockito.when(skuMockB.getPropertyValue("skuType")).thenReturn(ActiveSkuDroplet.PJPROMIS);
Mockito.when(skuMockB.getPropertyValue(ESTConstants.SKU_MISC1)).thenReturn("skuCodeB");
Mockito.when(skuMockB.getPropertyValue("displayName")).thenReturn("skuBDisplayName");
}
So when you then call this within a test it will be something like this:
Mockito.when(someMethodThatReturnsAList).thenReturn(skuList);
So the key really is that you are not mocking the List but instead the contents of the List.
Creating a mock using mockito is a good option.
But I am here explaining a different way of mocking the repository item.
Create a common implementation for RepositoryItem, say MockRepositoryItemImpl like this in your test package.
Public MockRepositoryItemImpl implements RepositoryItem {
private Map<String, Object> properties;
MockRepositoryItemImpl(){
properties = new HashMap<>();
}
#override
public Object getPropertyValue(String propertyName){
return properties.get(propertyName);
}
#override
public void setPropertyValue(String propertyName, Object propertyValue){
properties.put(propertyName, propertyValue);
}
}
Use this implementation to create the mock object in your test case.
RepositoryItem mockSKU = new MockRepositoryItemImpl();
mockSKU.setPropertyValue("id", "sku0001");
mockSKU.setPropertyValue("displayName", "Mock SKU");
mockSKU.setPropertyValue("skuType", "Type1");
mockSKU.setPropertyValue("isActive", "1");

How to compare two URLs in java?

Here's a simple problem - given two urls, is there some built-in method, or an Apache library that decides whether they are (logically) equal?
For example, these two urls are equal:
http://stackoverflow.com
http://stackoverflow.com/
While URI.equals() (as well as the problematic URL.equals()) does not return true for these specific examples, I think it's the only case where equivalence can be assumed (because there is no empty path in the HTTP protocol).
The URIs http://stackoverflow.com/foo and http://stackoverflow.com/foo/ can not be assumed to be equivalent.
Maybe you can use URI.equals() wrapped in a utility method that handles this specific case explicitly.
URL::equals reference
URL urlOne = new URL("http://stackoverflow.com");
URL urlTwo = new URL("http://stackoverflow.com/");
if( urlOne.equals(urlTwo) )
{
// ....
}
Note from docs -
Two URL objects are equal if they have the same protocol, reference equivalent hosts, have the same port number on the host, and the same file and fragment of the file.
Two hosts are considered equivalent if both host names can be resolved into the same IP addresses; else if either host name can't be resolved, the host names must be equal without regard to case; or both host names equal to null.
Since hosts comparison requires name resolution, this operation is a blocking operation.
Note: The defined behavior for equals is known to be inconsistent with virtual hosting in HTTP.
So, instead you should prefer URI::equals reference as #Joachim suggested.
The following may work for you - it validates that 2 urls are equal, allows the parameters to be supplied in different orders, and allows a variety of options to be configured, that being:
Is the host case sensitive
Is the path case sensitive
Are query string parameters case sensitive
Are query string values case sensitive
Is the scheme case sensitive
You can test it like so:
class Main {
public static void main(String[] args)
{
UrlComparer urlComparer = new UrlComparer();
expectResult(false, "key a case different", urlComparer.urlsMatch("//test.com?A=a&B=b", "//test.com?a=a&b=b"));
expectResult(false, "key a case different", urlComparer.urlsMatch("https://WWW.TEST.COM?A=1&b=2", "https://www.test.com?b=2&a=1"));
expectResult(false, "key a value different", urlComparer.urlsMatch("/test?a=2&A=A", "/test?a=A&a=2"));
expectResult(false, "key a value different", urlComparer.urlsMatch("https://WWW.TEST.COM?A=a&b=2", "https://www.test.com?b=2&A=1"));
expectResult(false, "null", urlComparer.urlsMatch("/test", null));
expectResult(false, "null", urlComparer.urlsMatch(null, "/test"));
expectResult(false, "port different", urlComparer.urlsMatch("//test.com:22?A=a&B=b", "//test.com:443?A=a&B=b"));
expectResult(false, "port different", urlComparer.urlsMatch("https://WWW.TEST.COM:8443", "https://www.test.com"));
expectResult(false, "protocol different", urlComparer.urlsMatch("http://WWW.TEST.COM:2121", "https://www.test.com:2121"));
expectResult(false, "protocol different", urlComparer.urlsMatch("http://WWW.TEST.COM?A=a&b=2", "https://www.test.com?b=2&A=a"));
expectResult(true, "both null", urlComparer.urlsMatch(null, null));
expectResult(true, "host and scheme different case", urlComparer.urlsMatch("HTTPS://WWW.TEST.COM", "https://www.test.com"));
expectResult(true, "host different case", urlComparer.urlsMatch("https://WWW.TEST.COM:443", "https://www.test.com"));
expectResult(true, "identical urls", urlComparer.urlsMatch("//test.com:443?A=a&B=b", "//test.com:443?A=a&B=b"));
expectResult(true, "identical urls", urlComparer.urlsMatch("/test?a=A&a=2", "/test?a=A&a=2"));
expectResult(true, "identical urls", urlComparer.urlsMatch("https://www.test.com", "https://www.test.com"));
expectResult(true, "parameter order changed", urlComparer.urlsMatch("https://www.test.com?a=1&b=2&c=522%2fMe", "https://www.test.com?c=522%2fMe&b=2&a=1"));
expectResult(true, "parmeter order changed", urlComparer.urlsMatch("https://WWW.TEST.COM?a=1&b=2", "https://www.test.com?b=2&a=1"));
}
public static void expectResult(boolean expectedResult, String msg, boolean result)
{
if (expectedResult != result)
throw new RuntimeException(msg);
}
}
UrlComparer.java
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
public class UrlComparer
{
private boolean hostIsCaseSensitive = false;
private boolean pathIsCaseSensitive = true;
private boolean queryStringKeysAreCaseSensitive = true;
private boolean queryStringValuesAreCaseSensitive = false;
private boolean schemeIsCaseSensitive = false;
public boolean urlsMatch(String url1, String url2)
{
try
{
if (Objects.equals(url1, url2))
return true;
URI uri1 = new URI(url1);
URI uri2 = new URI(url2);
// Compare Query String Parameters
Map<String, String> mapParams1 = getQueryStringParams(uri1);
Map<String, String> mapParams2 = getQueryStringParams(uri2);
if (!mapsAreEqual(mapParams1, mapParams2, getQueryStringValuesAreCaseSensitive()))
return false;
// Compare scheme (http or https)
if (!stringsAreEqual(uri1.getScheme(), uri2.getScheme(), getSchemeIsCaseSensitive()))
return false;
// Compare host
if (!stringsAreEqual(uri1.getHost(), uri2.getHost(), getHostIsCaseSensitive()))
return false;
// Compare path
if (!stringsAreEqual(uri1.getPath(), uri2.getPath(), getPathIsCaseSensitive()))
return false;
// Compare ports
if (!portsAreEqual(uri1, uri2))
return false;
return true;
}
catch (Exception e)
{
return false;
}
}
protected Map<String, String> getQueryStringParams(URI uri)
{
Map<String, String> result = getListAsMap(URLEncodedUtils.parse(uri, "UTF-8"), getQueryStringKeysAreCaseSensitive());
return result;
}
protected boolean stringsAreEqual(String s1, String s2, boolean caseSensitive)
{
// Eliminate null cases
if (s1 == null || s2 == null)
{
if (s1 == s2)
return true;
return false;
}
if (caseSensitive)
{
return s1.equals(s2);
}
return s1.equalsIgnoreCase(s2);
}
protected boolean mapsAreEqual(Map<String, String> map1, Map<String, String> map2, boolean caseSensitiveValues)
{
for (Map.Entry<String, String> entry : map1.entrySet())
{
String key = entry.getKey();
String map1value = entry.getValue();
String map2value = map2.get(key);
if (!stringsAreEqual(map1value, map2value, caseSensitiveValues))
return false;
}
for (Map.Entry<String, String> entry : map2.entrySet())
{
String key = entry.getKey();
String map2value = entry.getValue();
String map1value = map2.get(key);
if (!stringsAreEqual(map1value, map2value, caseSensitiveValues))
return false;
}
return true;
}
protected boolean portsAreEqual(URI uri1, URI uri2)
{
int port1 = uri1.getPort();
int port2 = uri2.getPort();
if (port1 == port2)
return true;
if (port1 == -1)
{
String scheme1 = (uri1.getScheme() == null ? "http" : uri1.getScheme()).toLowerCase();
port1 = scheme1.equals("http") ? 80 : 443;
}
if (port2 == -1)
{
String scheme2 = (uri2.getScheme() == null ? "http" : uri2.getScheme()).toLowerCase();
port2 = scheme2.equals("http") ? 80 : 443;
}
boolean result = (port1 == port2);
return result;
}
protected Map<String, String> getListAsMap(List<NameValuePair> list, boolean caseSensitiveKeys)
{
Map<String, String> result;
if (caseSensitiveKeys)
{
result = new HashMap<String, String>();
}
else
{
result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
}
for (NameValuePair param : list)
{
if (caseSensitiveKeys)
{
if (!result.containsKey(param.getName()))
result.put(param.getName(), param.getValue());
}
else
{
result.put(param.getName(), param.getValue());
}
}
return result;
}
public boolean getSchemeIsCaseSensitive()
{
return schemeIsCaseSensitive;
}
public void setSchemeIsCaseSensitive(boolean schemeIsCaseSensitive)
{
this.schemeIsCaseSensitive = schemeIsCaseSensitive;
}
public boolean getHostIsCaseSensitive()
{
return hostIsCaseSensitive;
}
public void setHostIsCaseSensitive(boolean hostIsCaseSensitive)
{
this.hostIsCaseSensitive = hostIsCaseSensitive;
}
public boolean getPathIsCaseSensitive()
{
return pathIsCaseSensitive;
}
public void setPathIsCaseSensitive(boolean pathIsCaseSensitive)
{
this.pathIsCaseSensitive = pathIsCaseSensitive;
}
public boolean getQueryStringKeysAreCaseSensitive()
{
return queryStringKeysAreCaseSensitive;
}
public void setQueryStringKeysAreCaseSensitive(boolean queryStringKeysAreCaseSensitive)
{
this.queryStringKeysAreCaseSensitive = queryStringKeysAreCaseSensitive;
}
public boolean getQueryStringValuesAreCaseSensitive()
{
return queryStringValuesAreCaseSensitive;
}
public void setQueryStringValuesAreCaseSensitive(boolean queryStringValuesAreCaseSensitive)
{
this.queryStringValuesAreCaseSensitive = queryStringValuesAreCaseSensitive;
}
}
sameFile
public boolean sameFile(URL other)Compares two URLs,
excluding the fragment component.
Returns true if this URL and the other argument are equal without taking the fragment component into consideration.
Parameters:
other - the URL to compare against.
Returns:
true if they reference the same remote object; false otherwise.
also please go through this link
http://download.oracle.com/javase/6/docs/api/java/net/URL.html#sameFile(java.net.URL)
As iam unable to add comment , browser throwing Javascript error. so iam adding my comment here. regret for inconvience.
//this what i suggeted
>URL url1 = new URL("http://stackoverflow.com/foo");
>URL url2 = new URL("http://stackoverflow.com/foo/");
>System.out.println(url1.sameFile(url2));
// this is suggested by Joachim Sauer
>URI uri = new URI("http://stackoverflow.com/foo/");
>System.out.println(uri.equals("http://stackoverflow.com/foo"));
// Both are giving same result
so Joachim Sauer check once.

Categories