I am experiencing some troubles when executing a for loop. The loop is called twice. Here is the code that does the work:
import java.util.ArrayList;
import java.util.List;
public class PoolItemMapper {
public List<Item> mapJsonObjectsToItems(JsonResponse jsonResponse) {
int count = 0;
List<Item> itemsList = new ArrayList<>();
List<Item> js = jsonResponse.getItems();
for (Item item : jsonResponse.getItems()) {
itemsList.add(addNormalItemProperties(item, new Item()));
count++;
}
System.out.println("Call count: " + count);
return itemsList;
}
private Item addNormalItemProperties(Item oldItem, Item newItem) {
if(oldItem.getMembersReference().getItems().size() <= 0) {
return oldItem;
} else if (oldItem.getMembersReference().getItems().size() > 0) {
for (SubItem subItem: oldItem.getMembersReference().getItems()) {
oldItem.getSubItems().add(creteNewSubItem(subItem));
}
}
return oldItem;
}
private Item creteNewSubItem(SubItem oldItem) {
Item i = new Item();
i.setDynamicRatio(oldItem.getDynamicRatio());
i.setEphermal(oldItem.getEphermal());
i.setInheritProfile(oldItem.getInheritProfile());
i.setLogging(oldItem.getLogging());
i.setRateLimit(oldItem.getRateLimit());
i.setRatio(oldItem.getRatio());
i.setSession(oldItem.getSession());
i.setAddress(oldItem.getAddress());
i.setName(oldItem.getName());
i.setState(oldItem.getState());
return i;
}
}
The list has a size of 134, so I receive an output of two times 'Call count 134'. This results in having duplicates in the list.
Here are the POJOs:
JSON response where getItems() for the foor loop is called:
public class JsonResponse {
private String kind;
private String selfLink;
private List<Item> items = new ArrayList<Item>();
public JsonResponse() {
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public String getSelfLink() {
return selfLink;
}
public void setSelfLink(String selfLink) {
this.selfLink = selfLink;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
The Item class is a simple DTO, containing only variables and their getters/setters:
Here is where the method is invoked:
itemTree = new PoolTreeBuilderImpl().buildTree(j);
itemTree.stream().forEach(i -> {
System.out.println("[PARENT] " + i.getData().toString());
i.getData().getSubItems().stream().forEach(si -> {
System.out.println(" [CHILD] " + si.toString());
});
});
}
and the PoolTreeBuilderImpl calls:
#Override
public List<TreeNode<Item>> buildTree(JsonResponse jsonResponse) {
List<TreeNode<Item>> itemTree = new ArrayList<>();
List<Item> mappedItems = new PoolItemMapper().mapJsonObjectsToItems(jsonResponse);
for (Item i : mappedItems) {
TreeNode<Item> item = new TreeNode<>(i);
if (i.getSubItems().size() > 0) {
for (Item subItem : i.getSubItems()) {
item.addChild(subItem);
}
}
itemTree.add(item);
}
return itemTree;
}
Could someone explain me why this loop is called twice resulting in having each subitem twice in the list?
Update
When executing this code, I don't have the duplicates:
List<Item> mappedItems = new PoolItemMapper().mapJsonObjectsToItems(jsonResponse);
mappedItems.forEach(i -> {
System.out.println("[PARENT] " + i.toString());
i.getMembersReference().getItems().forEach(s -> {
System.out.println(" [CHILD] " + s.toString());
});
});
The problem lies in the JsonResponse object, which is always the same. The objects within the JsonResponse list are modified twice, so there are duplicates. That is why (#Joakim Danielson) there is the second parameter newItem.
Additionally I had to change the signature of the buildTree method of the TreeBuilder to accept a list of Items, the one returned by the mapper.
Related
Im using Flink with Java to make my recommendation system using our logic.
So i have a dataset:
[user] [item]
100 1
100 2
100 3
100 4
100 5
200 1
200 2
200 3
200 6
300 1
300 6
400 7
So i map all to a tuple :
DataSet<Tuple3<Long, Long, Integer>> csv = text.flatMap(new LineSplitter()).groupBy(0, 1).reduceGroup(new GroupReduceFunction<Tuple2<Long, Long>, Tuple3<Long, Long, Integer>>() {
#Override
public void reduce(Iterable<Tuple2<Long, Long>> iterable, Collector<Tuple3<Long, Long, Integer>> collector) throws Exception {
Long customerId = 0L;
Long itemId = 0L;
Integer count = 0;
for (Tuple2<Long, Long> item : iterable) {
customerId = item.f0;
itemId = item.f1;
count = count + 1;
}
collector.collect(new Tuple3<>(customerId, itemId, count));
}
});
After i get all Customers and is Items inside arraylist:
DataSet<CustomerItems> customerItems = csv.groupBy(0).reduceGroup(new GroupReduceFunction<Tuple3<Long, Long, Integer>, CustomerItems>() {
#Override
public void reduce(Iterable<Tuple3<Long, Long, Integer>> iterable, Collector<CustomerItems> collector) throws Exception {
ArrayList<Long> newItems = new ArrayList<>();
Long customerId = 0L;
for (Tuple3<Long, Long, Integer> item : iterable) {
customerId = item.f0;
newItems.add(item.f1);
}
collector.collect(new CustomerItems(customerId, newItems));
}
});
Now i need get all "similar" customers. But after try a lot of things, nothing work.
The logic will be:
for ci : CustomerItems
c1 = c1.customerId
for ci2 : CustomerItems
c2 = ci2.cstomerId
if c1 != c2
if c2.getItems() have any item inside c1.getItems()
collector.collect(new Tuple2<c1, c2>)
I tried it using reduce, but i cant iterate on iterator two time (loop inside loop).
Can anyone help me?
You can cross the dataset with itself and basically insert your logic 1:1 into a cross function (excluding the 2 loops since the cross does that for you).
I solve the problem, but i need group and reduce after the "cross". I dont know that it is the best method. Can anyone suggest something?
The result is here:
package org.myorg.quickstart;
import org.apache.flink.api.common.functions.CrossFunction;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.GroupReduceFunction;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.util.Collector;
import java.io.Serializable;
import java.util.ArrayList;
public class UserRecommendation {
public static void main(String[] args) throws Exception {
final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// le o arquivo cm o dataset
DataSet<String> text = env.readTextFile("/Users/paulo/Downloads/dataset.csv");
// cria tuple com: customer | item | count
DataSet<Tuple3<Long, Long, Integer>> csv = text.flatMap(new LineFieldSplitter()).groupBy(0, 1).reduceGroup(new GroupReduceFunction<Tuple2<Long, Long>, Tuple3<Long, Long, Integer>>() {
#Override
public void reduce(Iterable<Tuple2<Long, Long>> iterable, Collector<Tuple3<Long, Long, Integer>> collector) throws Exception {
Long customerId = 0L;
Long itemId = 0L;
Integer count = 0;
for (Tuple2<Long, Long> item : iterable) {
customerId = item.f0;
itemId = item.f1;
count = count + 1;
}
collector.collect(new Tuple3<>(customerId, itemId, count));
}
});
// agrupa os items do customer dentro do customer
final DataSet<CustomerItems> customerItems = csv.groupBy(0).reduceGroup(new GroupReduceFunction<Tuple3<Long, Long, Integer>, CustomerItems>() {
#Override
public void reduce(Iterable<Tuple3<Long, Long, Integer>> iterable, Collector<CustomerItems> collector) throws Exception {
ArrayList<Long> newItems = new ArrayList<>();
Long customerId = 0L;
for (Tuple3<Long, Long, Integer> item : iterable) {
customerId = item.f0;
newItems.add(item.f1);
}
collector.collect(new CustomerItems(customerId, newItems));
}
});
// obtém todos os itens do customer que pertence a um usuário parecido
DataSet<CustomerItems> ci = customerItems.cross(customerItems).with(new CrossFunction<CustomerItems, CustomerItems, CustomerItems>() {
#Override
public CustomerItems cross(CustomerItems customerItems, CustomerItems customerItems2) throws Exception {
if (!customerItems.customerId.equals(customerItems2.customerId)) {
boolean has = false;
for (Long item : customerItems2.items) {
if (customerItems.items.contains(item)) {
has = true;
break;
}
}
if (has) {
for (Long item : customerItems2.items) {
if (!customerItems.items.contains(item)) {
customerItems.ritems.add(item);
}
}
}
}
return customerItems;
}
}).groupBy(new KeySelector<CustomerItems, Long>() {
#Override
public Long getKey(CustomerItems customerItems) throws Exception {
return customerItems.customerId;
}
}).reduceGroup(new GroupReduceFunction<CustomerItems, CustomerItems>() {
#Override
public void reduce(Iterable<CustomerItems> iterable, Collector<CustomerItems> collector) throws Exception {
CustomerItems c = new CustomerItems();
for (CustomerItems current : iterable) {
c.customerId = current.customerId;
for (Long item : current.ritems) {
if (!c.ritems.contains(item)) {
c.ritems.add(item);
}
}
}
collector.collect(c);
}
});
ci.first(100).print();
System.out.println(ci.count());
}
public static class CustomerItems implements Serializable {
public Long customerId;
public ArrayList<Long> items = new ArrayList<>();
public ArrayList<Long> ritems = new ArrayList<>();
public CustomerItems() {
}
public CustomerItems(Long customerId, ArrayList<Long> items) {
this.customerId = customerId;
this.items = items;
}
#Override
public String toString() {
StringBuilder itemsData = new StringBuilder();
if (items != null) {
for (Long item : items) {
if (itemsData.length() == 0) {
itemsData.append(item);
} else {
itemsData.append(", ").append(item);
}
}
}
StringBuilder ritemsData = new StringBuilder();
if (ritems != null) {
for (Long item : ritems) {
if (ritemsData.length() == 0) {
ritemsData.append(item);
} else {
ritemsData.append(", ").append(item);
}
}
}
return String.format("[ID: %d, Items: %s, RItems: %s]", customerId, itemsData, ritemsData);
}
}
public static final class LineFieldSplitter implements FlatMapFunction<String, Tuple2<Long, Long>> {
#Override
public void flatMap(String value, Collector<Tuple2<Long, Long>> out) {
// normalize and split the line
String[] tokens = value.split("\t");
if (tokens.length > 1) {
out.collect(new Tuple2<>(Long.valueOf(tokens[0]), Long.valueOf(tokens[1])));
}
}
}
}
Link with gist:
https://gist.github.com/prsolucoes/b406ae98ea24120436954967e37103f6
i have a method that puts some value(obtained from an excel file) into a hashmap with an array as the key
public HashMap<List<String>, List<String[]>> sbsBusServiceDataGnr() throws
IOException
{
System.out.println(engine.txtY + "Processing HashMap "
+ "sbsBusServiceData..." + engine.txtN);
int counterPass = 0, counterFail = 0, stopCounter = 0;
String dataExtract, x = "";
String[] stopInfo = new String[3];
List<String[]> stopsData = new ArrayList<String[]>();
List<String> serviceNum = new Vector<String>();
HashMap<List<String>, List<String[]>> sbsBusServiceData =
new HashMap<List<String>, List<String[]>>();
String dataPath = this.dynamicPathFinder(
"Data\\SBS_Bus_Routes.csv");
BufferedReader sbsBusServiceDataPop = new BufferedReader(
new FileReader(dataPath));
sbsBusServiceDataPop.readLine();
//Skips first line
while ((dataExtract = sbsBusServiceDataPop.readLine()) != null) {
try {
String[] dataParts = dataExtract.split(",", 5);
if (!dataParts[4].equals("-")){
if (Double.parseDouble(dataParts[4]) == 0.0){
sbsBusServiceData.put(serviceNum, stopsData);
String serviceNum1 = "null", serviceNum2 = "null";
if(!serviceNum.isEmpty()){
serviceNum1 = serviceNum.get(0);
serviceNum2 = serviceNum.get(1);
}
System.out.println("Service Number " + serviceNum1
+ ":" + serviceNum2 + " with " + stopCounter
+ " stops added.");
stopCounter = 0;
//Finalizing previous service
serviceNum.Clear();
serviceNum.add(0, dataParts[0]);
serviceNum.add(1, dataParts[1]);
//Adding new service
}
}
stopInfo[0] = dataParts[2];
stopInfo[1] = dataParts[3];
stopInfo[2] = dataParts[4];
stopsData.add(stopInfo);
//Adding stop to service
stopCounter++;
counterPass++;
}
catch (Exception e) {
System.out.println(engine.txtR + "Unable to process "
+ dataExtract + " into HashMap sbsBusServiceData."
+ engine.txtN + e);
counterFail++;
}
}
sbsBusServiceDataPop.close();
System.out.println(engine.txtG + counterPass + " number of lines"
+ " processed into HashMap sbsBusServiceData.\n" + engine.txtR
+ counterFail + " number of lines failed to process into "
+ "HashMap sbsBusServiceData.");
return sbsBusServiceData;
}
//Generates sbsBusServiceDataGnr HashMap : 15376 Data Rows
//HashMap Contents: {ServiceNumber, Direction},
// <{RouteSequence, bsCode, Distance}>
this method work for putting the values into the hashmap but i cannot seem to get any value from the hashmap when i try to call it there is always a nullpointerexception
List<String> sbsTest = new Vector<String>();
sbsTest.add(0, "10");
sbsTest.add(1, "1");
System.out.println(sbsBusServiceData.get(sbsTest));
try{
List<String[]> sbsServiceResults = sbsBusServiceData.get(sbsTest);
System.out.println(sbsServiceResults.size());
String x = sbsServiceResults.get(1)[0];
System.out.println(x);
} catch(Exception e){
System.out.println(txtR + "No data returned" + txtN + e);
}
this is a sample of the file im reading the data from:
SBS
How can i get the hashmap to return me the value i want?
Arrays are not suitable as keys in HashMaps, since arrays don't override Object's equals and hashCode methods (which means two different array instances containing the exact same elements will be considered as different keys by HashMap).
The alternatives are to use a List<String> instead of String[] as the key of the HashMap, or to use a TreeMap<String[]> with a custom Comparator<String[]> passed to the constructor.
If you are having fixed array size then the example I'm posting might be useful.
Here I've created two Object one is Food and Next is Product.
Here Food object is use and added method to get string array.
public class Product {
private String productName;
private String productCode;
public Product(String productName, String productCode) {
this.productName = productName;
this.productCode = productCode;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductCode() {
return productCode;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
}
Food Model Class: Use as a Object instead of String[] and achieve String[] functionality.
public class Food implements Comparable<Food> {
private String type;
private String consumeApproach;
public Food(String type, String consumeApproach) {
this.type = type;
this.consumeApproach = consumeApproach;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getConsumeApproach() {
return consumeApproach;
}
public void setConsumeApproach(String consumeApproach) {
this.consumeApproach = consumeApproach;
}
public String[] FoodArray() {
return new String[] { this.type, this.consumeApproach };
}
//Implement compareTo method as you want.
#Override
public int compareTo(Food o) {
return o.getType().compareTo(this.type);
}
}
Using HashMap example
public class HashMapKeyAsArray {
public static void main(String[] args) {
HashMap<Food,List<Product>> map = dataSetLake();
map.entrySet().stream().forEach(m -> {
String[] food = m.getKey().FoodArray();
Arrays.asList(food).stream().forEach(f->{
System.out.print(f + " ");
});
System.out.println();
List<Product> list = m.getValue();
list.stream().forEach(e -> {
System.out.println("Name:" + e.getProductName() + " Produc Code:" + e.getProductCode());
});
System.out.println();
});
}
private static HashMap<Food,List<Product>> dataSetLake(){
HashMap<Food,List<Product>> data = new HashMap<>();
List<Product> fruitA = new ArrayList<>();
fruitA.add(new Product("Apple","123"));
fruitA.add(new Product("Banana","456"));
List<Product> vegetableA = new ArrayList<>();
vegetableA.add(new Product("Potato","999"));
vegetableA.add(new Product("Tomato","987"));
List<Product> fruitB = new ArrayList<>();
fruitB.add(new Product("Apple","123"));
fruitB.add(new Product("Banana","456"));
List<Product> vegetableB = new ArrayList<>();
vegetableB.add(new Product("Potato","999"));
vegetableB.add(new Product("Tomato","987"));
Food foodA = new Food("Fruits","Read To Eat");
Food foodB = new Food("Vegetables","Need To Cook");
Food foodC = new Food("VegetablesC","Need To Cook C");
data.put(foodA, fruitB);
data.put(foodB, vegetableB);
data.put(foodA, fruitA);
data.put(foodC, vegetableA);
return data;
}
Using TreeMap example
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;
public class TreeMapKeyAsArray {
public static void main(String[] args) {
TreeMap<Food, List<Product>> map = dataSetLake();
map.entrySet().stream().forEach(m -> {
String[] food = m.getKey().FoodArray();
Arrays.asList(food).stream().forEach(f->{
System.out.print(f + " ");
});
System.out.println();
List<Product> list = m.getValue();
list.stream().forEach(e -> {
System.out.println("Name:" + e.getProductName() + " Produc Code:" + e.getProductCode());
});
System.out.println();
});
}
private static TreeMap<Food, List<Product>> dataSetLake() {
TreeMap<Food, List<Product>> data = new TreeMap<>();
List<Product> fruitA = new ArrayList<>();
fruitA.add(new Product("Apple", "123"));
fruitA.add(new Product("Banana", "456"));
List<Product> vegetableA = new ArrayList<>();
vegetableA.add(new Product("Potato", "999"));
vegetableA.add(new Product("Tomato", "987"));
List<Product> fruitB = new ArrayList<>();
fruitB.add(new Product("Apple", "123"));
fruitB.add(new Product("Banana", "456"));
List<Product> vegetableB = new ArrayList<>();
vegetableB.add(new Product("Potato", "999"));
vegetableB.add(new Product("Tomato", "987"));
Food foodA = new Food("Fruits", "Read To Eat");
Food foodB = new Food("Vegetables", "Need To Cook");
data.put(foodA, fruitB);
data.put(foodB, vegetableB);
data.put(foodA, fruitA);
data.put(foodB, vegetableA);
return data;
}
}
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.
I'm really a newbie to JAVA, spring mvc.
And my understanding for "code" is so poor that I can't even think of how I'm going to get through with upcoming errors.
So this question will sound like " Do this for me!". ( It will do, actually )
Anyway, I'm trying to make a two-depth menu. Its structure looks like this below.
TopMenu
::: menuNo
::: menuName
::: memberType
::: url
::: sort
::: subMenus
::: menuNo
::: menuName
::: memberType
::: url
::: sort
TopMenu2
::: menuNo2
::: menuName2
::: memberType2
::: url2
.
.
.
.
So I made a bean class for this.
public class MenuInfoBean {
private String menuNo;
private String menuName;
private String memberType;
private String url;
private int sort;
List<MenuInfoBean> subMenus;
public MenuInfoBean() {
}
public String getMenuNo() {
return menuNo;
}
public void setMenuNo(String menuNo) {
this.menuNo = menuNo;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMemberType() {
return memberType;
}
public void setMemberType(String memberType) {
this.memberType = memberType;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getSort() {
return sort;
}
public void setSort(int sort) {
this.sort = sort;
}
public List<MenuInfoBean> getSubMenus() {
return subMenus;
}
public void setSubMenus(MenuInfoBean subMenus) {
subMenus.menuName = subMenus.menuName;
subMenus.memberType = subMenus.memberType;
subMenus.url = subMenus.url;
subMenus.sort = subMenus.sort;
}
}
Which database will be used is not decided yet, so I'm temporarily using properties for menu data.
#TopMenu List
topmenu = M1000,M9000
#SubMenu List
M1000.submenu =
M9000.submenu = M9001,M9002,M9003,M9004
#TopMenu Info
#M1000 APPLICATION
M1000.menuName=APPLICATION
M1000.url=
M1000.memberType=00,10
M1000.sort=1
#M9000 ADMIN
M9000.menuName=ADMIN
M9000.url=/SYS01/memberList.mon
M9000.memberType=00,10
M9000.sort=1
#SubMenu Info
#M9000 ADMIN's
M9001.menuName=Member mgmt
M9001.url=/SYS01/memberList.mon
M9001.memberType=00,10
M9001.sort=1
M9002.menuName=menu2
M9002.url=/SYS01/memberList.mon
M9002.memberType=00,10
M9002.sort=1
M9003.menuName=menu3
M9003.url=/SYS01/memberList.mon
M9003.memberType=00,10
M9003.sort=1
M9004.menuName=menu4
M9004.url=/SYS01/memberList.mon
M9004.memberType=00,10
M9004.sort=1
And here I fetch the data and try to put them into a List.
public class MenuManager {
public List<MenuInfoBean> getMenus(String permissionCode) {
LabelProperties msgResource = LabelProperties.getInstance();
MenuInfoBean menuInfo = new MenuInfoBean();
List<MenuInfoBean> menuList = new ArrayList<MenuInfoBean>();
String topMenu = msgResource.getProperty("topmenu");
String[] topMenuItems = topMenu.split(",");
for (int i = 0; topMenuItems.length > i; i++ ) {
String subMenuName = msgResource.getProperty(topMenuItems[i] + ".submenu");
if ( subMenuName.isEmpty() == false ) {
menuInfo.setMenuName(msgResource.getProperty(subMenuName + ".menuName"));
menuInfo.setMemberType(msgResource.getProperty(subMenuName + ".memberType"));
menuInfo.setUrl(msgResource.getProperty(subMenuName + ".url"));
menuInfo.setSort(Integer.parseInt(msgResource.getProperty(subMenuName + ".sort")));
menuInfo.setSubMenus(menuInfo);
} else {
menuInfo.setMenuName("");
menuInfo.setSubMenus(menuInfo);
}
menuInfo.setMenuNo("");
menuInfo.setMenuName(msgResource.getProperty(topMenuItems[i] + ".menuName"));
menuInfo.setMemberType(msgResource.getProperty(topMenuItems[i] + ".memberType"));
menuInfo.setUrl(msgResource.getProperty(topMenuItems[i] + ".url"));
menuInfo.setSort(Integer.parseInt(msgResource.getProperty(topMenuItems[i] + ".sort")));
menuList.add(menuInfo);
}
return menuList;
}
}
getProperty method works great. It gets the properties value correctly.
But as you may noticed, there's some null data is being made.
to ignore this NullPointerException, I made
List<MenuInfoBean> menuList = new ArrayList<MenuInfoBean>();
So the exception has been successfully avoided. But another error comes up which isn't important in this post....
Anyway, while trying to solve the new error, I looked into the menuInfo data and found out something wrong was going on.
The subMenus was holding the topMenu's data!
Here's the question, How can I make this menu with MenuInfoBean like the structure I mentioned on the top of this post?
And why subMenus data was holding topMenu's properties?
I set subMenus data first, and topMenu data later! why this happens?
First of all I am updating the domain object by adding a additional method add(Meun)
import java.util.ArrayList;
import java.util.List;
public class MenuInfoBean
{
private String menuNo;
private String menuName;
private String memberType;
private String url;
private int sort;
List<MenuInfoBean> subMenus;
public MenuInfoBean()
{
}
public String getMenuNo()
{
return menuNo;
}
public void setMenuNo(String menuNo)
{
this.menuNo = menuNo;
}
public String getMenuName()
{
return menuName;
}
public void setMenuName(String menuName)
{
this.menuName = menuName;
}
public String getMemberType()
{
return memberType;
}
public void setMemberType(String memberType)
{
this.memberType = memberType;
}
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
public int getSort()
{
return sort;
}
public void setSort(int sort)
{
this.sort = sort;
}
public List<MenuInfoBean> getSubMenus()
{
return subMenus;
}
// This is new method added to the bean
public void addSubMenuItem(MenuInfoBean menuInfoBean)
{
if (subMenus == null)
subMenus = new ArrayList<MenuInfoBean>();
subMenus.add(menuInfoBean);
}
}
Here is the class that generate the menu and return (look at the get menu method):
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class MenuExtractionComponent
{
public List<MenuInfoBean> getMenus(String permissionCode)
{
LabelProperties msgResource = LabelProperties.getInstance();
List<MenuInfoBean> menuList = new ArrayList<MenuInfoBean>();
String topMenu = msgResource.getProperty("topmenu");
List<String> topMenuItems = new ArrayList<String>();
// Checking is top menu empty
if (StringUtils.isNotBlank(topMenu))
{
topMenuItems.addAll(Arrays.asList(topMenu.split(",")));
}
for (String topMenuItem : topMenuItems)
{
// Setting top menu details
MenuInfoBean menuInfo = new MenuInfoBean();
menuInfo.setMenuNo("");
menuInfo.setMenuName(msgResource.getProperty(topMenuItem + ".menuName"));
menuInfo.setMemberType(msgResource.getProperty(topMenuItem + ".memberType"));
menuInfo.setUrl(msgResource.getProperty(topMenuItem + ".url"));
menuInfo.setSort(Integer.parseInt(msgResource.getProperty(topMenuItem + ".sort")));
String subMenu = msgResource.getProperty(topMenuItem + ".submenu");
List<String> subMenuItems = new ArrayList<String>();
// Checking is sub menu empty
if (StringUtils.isNotBlank(subMenu))
{
subMenuItems.addAll(Arrays.asList(subMenu.split(",")));
}
for (String subMenuItem : subMenuItems)
{
MenuInfoBean subMenuInfo = new MenuInfoBean();
subMenuInfo.setMenuName(msgResource.getProperty(subMenuItem + ".menuName"));
subMenuInfo.setMemberType(msgResource.getProperty(subMenuItem + ".memberType"));
subMenuInfo.setUrl(msgResource.getProperty(subMenuItem + ".url"));
subMenuInfo.setSort(Integer.parseInt(msgResource.getProperty(subMenuItem + ".sort")));
menuInfo.addSubMenuItem(subMenuInfo);
}
menuList.add(menuInfo);
}
return menuList;
}
}
In another class im using the setRating to change the ratings of these songs, however I'm not sure what I need to do to this code to be able to change the rating permanently. Thanks in advance.
import java.util.*;
public class LibraryData {
static String playCount() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
static int setRating(int stars) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
private static class Item {
Item(String n, String a, int r) {
name = n;
artist = a;
rating = r;
}
// instance variables
private String name;
private String artist;
private int rating;
private int playCount;
public String toString() {
return name + " - " + artist;
}
}
// with a Map you use put to insert a key, value pair
// and get(key) to retrieve the value associated with a key
// You don't need to understand how this works!
private static Map<String, Item> library = new TreeMap<String, Item>();
static {
// if you want to have extra library items, put them in here
// use the same style - keys should be 2 digit Strings
library.put("01", new Item("How much is that doggy in the window", "Zee-J", 3));
library.put("02", new Item("Exotic", "Maradonna", 5));
library.put("03", new Item("I'm dreaming of a white Christmas", "Ludwig van Beethoven", 2));
library.put("04", new Item("Pastoral Symphony", "Cayley Minnow", 1));
library.put("05", new Item("Anarchy in the UK", "The Kings Singers", 0));
}
public static String listAll() {
String output = "";
Iterator iterator = library.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
Item item = library.get(key);
output += key + " " + item.name + " - " + item.artist + "\n";
}
return output;
}
public static String getName(String key) {
Item item = library.get(key);
if (item == null) {
return null; // null means no such item
} else {
return item.name;
}
}
public static String getArtist(String key) {
Item item = library.get(key);
if (item == null) {
return null; // null means no such item
} else {
return item.artist;
}
}
public static int getRating(String key) {
Item item = library.get(key);
if (item == null) {
return -1; // negative quantity means no such item
} else {
return item.rating;
}
}
public static void setRating(String key, int rating) {
Item item = library.get(key);
if (item != null) {
item.rating = rating;
}
}
public static int getPlayCount(String key) {
Item item = library.get(key);
if (item == null) {
return -1; // negative quantity means no such item
} else {
return item.playCount;
}
}
public static void incrementPlayCount(String key) {
Item item = library.get(key);
if (item != null) {
item.playCount += 1;
}
}
public static void close() {
// Does nothing for this static version.
// Write a statement to close the database when you are using one
}
}
Inside Item, you should write this method:
public static void setRating(int rating0) {
rating = rating0;
}
You should also change your instance variables into static variables by calling them "public static" instead of just "public."