public <ITEMS extends Items<ITEM>, ITEM extends Item> List<ITEM> getRecommendations(final List<ITEMS> itemsList, final ITEMS targetItems,
            final Class<ITEM> clazz)
            throws InstantiationException,
            IllegalAccessException {
        Map<Object, Double> scores = new HashMap<Object, Double>();
        Map<Object, Double> sumSimilarities = new HashMap<Object, Double>();

        for (ITEMS itemList : itemsList) {
            if (!itemList.getKey().equals(targetItems.getKey())) {
                double similarity = getSimilarity(itemList, targetItems);
                if (similarity <= 0.0d)
                    continue;

                for (Item item : itemList.getItems()) {
                    Item itemTarget = ItemUtil.getItemByKey(targetItems, item.getKey());
                    if (itemTarget == null || itemTarget.getValue() == 0.0d) {
                        scores.put(item.getKey(),
                                scores.containsKey(item.getKey()) ? scores.get(item.getKey()) + item.getValue() * similarity : item.getValue()
                                        * similarity);
                        sumSimilarities.put(item.getKey(),
                                sumSimilarities.containsKey(item.getKey()) ? sumSimilarities.get(item.getKey()) + similarity : similarity);
                    }
                }
            }
        }
        List<ITEM> recommendations = new ArrayList<ITEM>();

        for (Iterator<Entry<Object, Double>> it = scores.entrySet().iterator(); it.hasNext();) {
            Map.Entry<Object, Double> entry = (Map.Entry<Object, Double>) it.next();
            ITEM item = ItemUtil.createItemInstance(clazz, entry.getKey(), entry.getValue() / sumSimilarities.get(entry.getKey()));
            recommendations.add(item);
        }

        ItemUtil.sortByItemValue(recommendations);
        return recommendations;
    }