The line
associations.put("test1",B::setBeta);
below does not compile. I'm not clear why it won't work since B extends A. Is there a way to make this work? I'm trying to build a map of method references from an inheritance family.
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public enum Test {
ENUM0() {
#Override
public void init() {
associations.put("test0",A::setAlpha);
}
},
ENUM1() {
#Override
public void init() {
associations.put("test1",B::setBeta);
}
};
public abstract void init();
Map<String, BiConsumer<? extends A, String>> associations = new HashMap<>();
}
class A {
public String getAlpha() {
return alpha;
}
public void setAlpha(String alpha) {
this.alpha = alpha;
}
String alpha;
}
class B extends A {
public String getBeta() {
return beta;
}
public void setBeta(String beta) {
this.beta = beta;
}
String beta;
}
This seems like a curious case of type inference, explicitly tagging the expression resolves the compilation errors:
associations.put("test1", (BiConsumer<B, String>) B::setBeta);
Related
import com.google.common.collect.Multimap;
import java.util.Collection;
public class GenericsTest {
private final Multimap<String, Box<?>> boxMultimap;
public GenericsTest(Multimap<String, Box<?>> boxMultimap) {
this.boxMultimap = boxMultimap;
}
public <T> Collection<Box<T>> get(final String boxType) {
final Collection<Box<T>> boxes = boxMultimap.get(boxType);
return boxes;
}
}
Box:
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
How would I cast boxMultimap.get(boxType); to type <T> for this specific get example method. The above fails to retrieve from the multimap.
The following works just fine:
public class GenericsTest {
private final Multimap<String, Box> boxMultimap;
public GenericsTest(Multimap<String, Box> boxMultimap) {
this.boxMultimap = boxMultimap;
}
public <T> Collection<Box<T>> get(final String boxType) {
final Collection boxes = boxMultimap.get(boxType);
return boxes;
}
}
But I wanted to be explicit on the local boxes collection variable (final Collection<Box<T>> boxes = boxMultimap.get(boxType);).
I am trying to design a framework for loading resources. So I have two options
Approach 1
Underlying structure: An interface with a simple abstract class implementation and more specific extends.
Access: static final members of class initialized to the class.
Approach 2
Underlying structure: A specific enum from the get go, implementing all interface methods: no leveraging partial implementations of abstract classes.
Access: as enum entries
While approach 1 is a lot more flexible and reusable, I like the way enums provide a clean usable list, ready to use as opposed to static finals with scope for Class.instance.instance.instance. ...
Is there a standard way to do this? Is there a better way to do this?
Though not strictly needed here's the code
Approach 1
Interface LoadableResource<T>
import java.util.ArrayDeque;
import java.util.Queue;
public interface LoadableResource<T> {
Queue<Exception> exceptionQueue=new ArrayDeque<>();
boolean load();//Load the resource and return status
boolean isLoaded() ;
T getResource();
void onLoadFail();
void onLoadSuccess();
void onException(Exception ex);
Queue<Exception> getExcpetions();
}
Abstract SimpleLoadableResource<T>
import java.util.Queue;
public abstract class SimpleLoadableResource<T> implements LoadableResource<T> {
private boolean FLAG_LOADED = false;
private T resource;
#Override
public boolean isLoaded() {
return FLAG_LOADED;
}
#Override
public T getResource() {
return resource;
}
#Override
public void onLoadFail() {}
#Override
public void onLoadSuccess() {}
#Override
public void onException(Exception ex) {exceptionQueue.add(ex); }
#Override
public Queue<Exception> getExcpetions() { return exceptionQueue; }
protected void setLoaded(boolean FLAG_LOADED) {
this.FLAG_LOADED = FLAG_LOADED;
}
public abstract T loader() throws Exception;
#Override
public boolean load() {
try {
resource=loader();
} catch (Exception e) { onException(e); }
if (isLoaded())
onLoadSuccess();
else
onLoadFail();
return isLoaded();
}
}
Specific SimpleLoadableImage
import javax.imageio.ImageIO;
import java.awt.*;
public class SimpleLoadableImage extends SimpleLoadableResource<Image>{
public static final SimpleLoadableImage LOGO1=new SimpleLoadableImage("1.jpg");
public static final SimpleLoadableImage LOGO2=new SimpleLoadableImage("2.jpg");
private final String path;
public SimpleLoadableImage(String path) {
this.path = path;
super.load();
}
#Override
public Image loader() throws Exception {
var res=ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(path));
setLoaded(true);
return res;
}
}
Approach 2
import javax.imageio.ImageIO;
import java.awt.*;
import java.util.ArrayDeque;
import java.util.Queue;
public enum SimpleLoadableImage_Enum {
LOGO1("1.jpg"),
LOGO("2.jpg");
private final String path;
Queue<Exception> exceptionQueue=new ArrayDeque<>();
private boolean FLAG_LOADED = false;
private Image resource;
private SimpleLoadableImage_Enum(String path){
this.path=path;
try {
resource=ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(path));
FLAG_LOADED=true;
} catch (Exception e) {
exceptionQueue.add(e);
}
}
public boolean isLoaded() { return FLAG_LOADED; }
public Image getResource() { return resource; }
public Queue<Exception> getExcpetions() { return exceptionQueue; }
}
I created a java project to apply my GraphTheory course and enhance my java skills.
In this project :
I created a class Sommet<S>(Vertex in English) with an attribute Id with a generic type called <S>.
I created a class Arc<S>(Edge in English) with two attributes Sommet(Vertex).
I created a class EnsembleArc which is an HashSet of Arc
I also created a class ArcValue which inherit from Arc and have an int attribute Valeur(Value in English)
Here everything is fine and I dont have any problem.
But then I created a class EnsembleArcValue which inherit from EnsembleArc because every method from EnsembleArc will be useful to EnsembleArcValue.
But I also want EnsembleArcValue to be an HashSet of ArcValue (and I dont want an Arc which is not an ArcValue). And with the inheritance EnsembleArcValue is able to have an "simple" Arc in his Set.
So my question after all this explanation is :
Is there a way for EnsembleArcValue to inherit from EnsembleArc but will only accept an ArcValue in his Set.
Here is an image of The UML Project
I hope it will help to understand my problem (dont look at the bottom).
Here is the code :
public class Sommet<S>
{
//attributes
private S id;
public Sommet(S s)
{
setId(s);
}
public S getId()
{
return id;
}
public void setId(S s)
{
assert s!= null: "Objet null passé en paramètre";
id = s;
}
#SuppressWarnings("unchecked")
#Override
public boolean equals(Object obj)
{
boolean callback;
if(obj.getClass()!=getClass())
{
callback=false;
}
else
{
if(((Sommet<S>)obj).getId().equals(getId()))
{
callback=true;
}
else
{
callback=false;
}
}
return callback;
}
#Override
public int hashCode()
{
return getId().hashCode();
}
#Override
public String toString()
{
return getId().toString();
}
}
public class Arc<S>
{
private Sommet<S> depart;
private Sommet<S> arrivee;
public Arc(Sommet<S> dep, Sommet<S> arr)
{
setDepart(dep);
setArrivee(arr);
}
#Override
public String toString()
{
String str="("+getDepart().getId()+","+getArrivee().getId()+")";
return str;
}
public Sommet<S> getDepart()
{
return depart;
}
public Sommet<S> getArrivee()
{
return arrivee;
}
public void setDepart(Sommet<S> depart)
{
this.depart = depart;
}
public void setArrivee(Sommet<S> arrivee)
{
this.arrivee = arrivee;
}
#SuppressWarnings("unchecked")
#Override
public boolean equals(Object obj)
{
boolean callback;
if(obj.getClass()!=getClass())
{
callback=false;
}
else
{
if(((Arc<S>)obj).getDepart().equals(getDepart())&&((Arc<S>)obj).getArrivee().equals(getArrivee()))
{
callback=true;
}
else
{
callback=false;
}
}
return callback;
}
#Override
public int hashCode()
{
return getArrivee().hashCode()+getDepart().hashCode();
}
}
public class ArcValue<S,V> extends Arc<S>
{
private V valeur;
public ArcValue (Sommet<S> depart, Sommet<S> arrivee, V valeur)
{
super(arrivee,depart);
this.valeur=valeur;
}
public V getValeur()
{
return valeur;
}
}
import java.util.HashSet;
public class Ensemble<E> extends HashSet<E> implements Cloneable
{
private static final long serialVersionUID = -4354387895748449845L;
public Ensemble ()
{
super();
}
public Ensemble (Ensemble<E> ensemble)
{
for (E e : ensemble)
{
add(e);
}
}
public String toString()
{
StringBuffer str=new StringBuffer("{");
for(E e: this)
{
str=str.append(e.toString()+",");
}
str.setCharAt(str.length()-1, '}');
return str.toString();
}
#SuppressWarnings("unchecked")
#Override
public Ensemble<E> clone()
{
return (Ensemble<E>)super.clone();
}
}
public class EnsembleArc<S> extends Ensemble<Arc<S>>
{
public EnsembleArc(Ensemble<Arc<S>> ensemble)
{
super(ensemble);
}
public EnsembleArc()
{
super();
}
private static final long serialVersionUID = -4099925554493145279L;
public EnsembleSommet<S> listSucc(Sommet<S> sommet)
{
EnsembleSommet<S> XSucc=new EnsembleSommet<S>();
for (Arc<S> arc : this)
{
if (arc.getDepart()==sommet)
{
XSucc.add(arc.getArrivee());
}
}
return XSucc;
}
public EnsembleSommet<S> listPred(Sommet<S> sommet)
{
EnsembleSommet<S> XPred=new EnsembleSommet<S>();
for (Arc<S> arc : this)
{
if (arc.getArrivee()==sommet)
{
XPred.add(arc.getDepart());
}
}
return XPred;
}
public void add(Sommet<S> depart,Sommet<S>arrivee)
{
add(new Arc<S>(depart,arrivee));
}
#Override
public EnsembleArc<S> clone ()
{
return (EnsembleArc<S>)super.clone();
}
}
//import java.util.Collection;
public class EnsembleArcValues<S,V> extends EnsembleArc<S> //implements Collection<ArcValue<S,V>>
{
//TODO faire en sorte que ensembleArcValués ne contienne que des ArcsValue
private static final long serialVersionUID = -7163498825360866323L;
}
And you'll need this one to :
public class EnsembleSommet<S> extends Ensemble<Sommet<S>>
{
public EnsembleSommet()
{
super();
}
public EnsembleSommet(EnsembleSommet<S> ensemble)
{
super(ensemble);
}
private static final long serialVersionUID = 7278825382690341067L;
#Override
public EnsembleSommet<S> clone ()
{
return (EnsembleSommet<S>)super.clone();
}
public Sommet<S> firstSommet()
{
#SuppressWarnings("unchecked")
Sommet<S>[] tab=new Sommet[size()];
return toArray(tab)[0];
}
}
The only way you can achieve this is to make the type of Arc you want part of your generic deceleration. Rename your existing EnsembleArc to AbstractEnsembleArc and change it's generic decleration from < S > to < S, T extends Arc< S > > i.e.:
public abstract class AbstractEnsembleArc<S, T extends Arc<S>> extends Ensemble<T> {
// PUT ALL YOUR LOGIC CURRENTLY IN EnsembleArc HERE
}
Now create a new Class Called EnsembleArc and extend the new abstract class you've added, this new class will work identically to your existing EnsembleArc and class decleration should now look like:
public class EnsembleArc<S> extends AbstractEnsembleArc<S, Arc<S>> {
}
Finally have EnsembleArcValues extend the Abstract class instead of EnsembleArc so that you can declare that it should only accepts ArcValue and not simple Arc, do that like this:
public class EnsembleArcValues<S, V> extends AbstractEnsembleArc<S, ArcValue<S, V>> {
}
I want to check if all the ingredients(toppings and fillings) inside a wrap are both vegan and nut free. This is the solution that I came up with, howver I think its a bit inefficient as there is duplication of code. Is there a more efficient way to do it?
(I have a map for all the toppings and fillings which every one contains boolean to know if the topping/filling is vegan and if it is nut free.
public boolean isVegan() {
for (Topping t : toppings) {
if (!t.isVegan()) {
return false;
}
}
for (Filling f : fillings) {
if (!f.isVegan()) {
return false;
}
}
return bread.isVegan();
}
public boolean isNutFree() {
for (Topping t : toppings) {
if (!t.isNutFree()) {
return false;
}
}
for (Filling f : fillings) {
if (!f.isNutFree()) {
return false;
}
}
return bread.isNutFree();
}
Supposing that Ingredient is the base class of these different classes and that this class defines the isVegan() method, you could create a Stream from all these objects and computing whether all are vegan :
public boolean isVegan() {
return
Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
.allMatch(Ingredient::isVegan);
}
For isNutFree() the idea is the same :
public boolean isNutFree() {
return
Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
.allMatch(Ingredient::isNutFree);
}
Note that you could also generalize a matching method to reduce further the duplication :
public boolean allMatch(Predicate<Ingredient> predicate) {
return
Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
.allMatch( i -> predicate.test(i));
}
And use it such as :
boolean isNutFree = allMatch(Ingredient::isNutFree);
boolean isVegan = allMatch(Ingredient::isVegan);
Here is a food type replacing either Topping or Filling or anything:
public interface FoodPart {
boolean isVegan();
boolean isNutFree();
}
Here we have an abstract Food class containing all common codes:
public abstract class Food {
private List<? extends FoodPart> foodParts;
public boolean isVegan() {
return foodParts.stream().noneMatch(foodPart -> foodPart.isVegan());
}
public boolean isNutFree() {
return foodParts.stream().noneMatch(foodPart -> foodPart.isNutFree());
}
}
And here is a concrete and not abstract food:
public class Lasagne extends Food {}
Edit:
If you don't want to inherit from FoodPart then you can change List<? extends FoodPart> simply to List<FoodPart>.
You can also make Food to not abstract so you can easily use it, and don't forget to add getters/setters to provide the foodParts.
Yeez, you guys are fast :)
What I wrote is pretty much already covered in the other answers here but just posting since mine does have some subtle differences (not necessarily better). And since I already went through the motions of writing the code I might as well post it :)
First an interface for your fillings and toppings:
public interface FoodInformation {
boolean isVegan();
boolean isNutFree();
boolean isGlutenFree();
}
Then an abstract class which your toppings and fillings can extend:
public abstract class Ingredient implements FoodInformation {
private boolean vegan;
private boolean nutFree;
private boolean glutenFree;
public Ingredient(boolean vegan, boolean nutFree, boolean glutenFree) {
this.vegan = vegan;
this.nutFree = nutFree;
this.glutenFree = glutenFree;
}
#Override
public boolean isVegan() {
return vegan;
}
#Override
public boolean isNutFree() {
return nutFree;
}
#Override
public boolean isGlutenFree() {
return glutenFree;
}
}
Your Filling:
public class Filling extends Ingredient {
public Filling(boolean vegan, boolean nutFree, boolean glutenFree) {
super(vegan, nutFree, glutenFree);
}
}
Your Topping:
public class Topping extends Ingredient {
public Topping(boolean vegan, boolean nutFree, boolean glutenFree) {
super(vegan, nutFree, glutenFree);
}
}
And your Wrap:
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class Wrap {
private List<Filling> fillings;
private List<Topping> toppings;
public Wrap(List<Filling> fillings, List<Topping> toppings) {
this.fillings = fillings;
this.toppings = toppings;
}
public boolean isNutFree() {
return testIngredient(FoodInformation::isNutFree);
}
public boolean isVegan() {
return testIngredient(FoodInformation::isVegan);
}
public boolean isGlutenFree() {
return testIngredient(FoodInformation::isGlutenFree);
}
private boolean testIngredient(Predicate<FoodInformation> predicate) {
// edited thanks to davidxxx for the Stream.concat notation!
return Stream
.concat(fillings.stream(), toppings.stream())
.allMatch(predicate);
}
}
And a test to show the implementation works:
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;
public class WrapTest {
private Wrap wrap;
#Before
public void setup() {
Filling filling1 = new Filling(true, true, false);
Filling filling2 = new Filling(true, false, true);
Filling filling3 = new Filling(true, true, true);
Topping topping1 = new Topping(true, true, true);
wrap = new Wrap(Arrays.asList(filling1, filling2, filling3), Collections.singletonList(topping1));
}
#Test
public void testIsGlutenFree() {
assertFalse(wrap.isGlutenFree());
}
#Test
public void testIsNutFree() {
assertFalse(wrap.isNutFree());
}
#Test
public void testIsVegan() {
assertTrue(wrap.isVegan());
}
}
Have fun with your project!
create an interface that has isVegan and isNutFree
public interface MyInterface {
boolean isVegan();
boolean isNutFree();
}
Then each of your classes with implement your interface
public class Topping implements MyInterface {
#Override
public boolean isVegan() {
return isVegan;
}
#Override boolean isNutFree() {
return isNutFree;
}
}
public class Filling implements MyInterface {
#Override
public boolean isVegan() {
return isVegan;
}
#Override boolean isNutFree() {
return isNutFree;
}
}
Next create a method that can test the lists
public boolean isVegan(List<? extends MyInterface> list) {
for(MyInterface myObj : list) {
if (myObj.isVegan()) return true;
}
return false;
}
public boolean isNutFree(List<? extends MyInterface> list) {
for(MyInterface myObj: list) {
if (myObj.isNutFree()) return true;
}
return false;
}
then each list you can pass into the methods to get the results
Facing an issue with passing values from my html form to action class. Created a sample project to test the functionality and have the same issue here. I have the following classes:
TestBean
package com.struts2test.beans;
public class TestBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
TestBeanHolder
package com.struts2test.beans;
import java.util.List;
import java.util.Map;
public class TestBeanHolder {
private Map<Integer, TestBean> testBeanMap;
private List<TestBean> testBeanList;
private Map<Integer, List<TestBean>> testBeanListMap;
public Map<Integer, TestBean> getTestBeanMap() {
return testBeanMap;
}
public void setTestBeanMap(Map<Integer, TestBean> testBeanMap) {
this.testBeanMap = testBeanMap;
}
public Map<Integer, List<TestBean>> getTestBeanListMap() {
return testBeanListMap;
}
public void setTestBeanListMap(Map<Integer, List<TestBean>> testBeanListMap) {
this.testBeanListMap = testBeanListMap;
}
public List<TestBean> getTestBeanList() {
return testBeanList;
}
public void setTestBeanList(List<TestBean> testBeanList) {
this.testBeanList = testBeanList;
}
}
TestAction
package com.struts2test.action;
import com.opensymphony.xwork2.ActionSupport;
import com.struts2test.beans.TestBeanHolder;
public class TestAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private TestBeanHolder testBeanHolder;
public TestBeanHolder getTestBeanHolder() {
return testBeanHolder;
}
public void setTestBeanHolder(TestBeanHolder testBeanHolder) {
this.testBeanHolder = testBeanHolder;
}
public String execute() throws Exception {
return SUCCESS;
}
}
When my url is http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanMap[0].value=1, testBeanHolder.testBeanMap of my action gets populated with key of 0 mapping to a TestBean instance with value=1.
When the url is http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanList[0].value=1, testBeanHolder.testBeanList gets populated with single instance of TestBean with value=1.
I am try to populate testBeanListMap property of testBeanHolder and doesn't work. The testBeanListMap is created but empty. Here is the URL I am trying http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanListMap[0][0].value=1
Here is the code which worked, adding modified classes:
TestBeanListHolder
package com.struts2test.beans;
import java.util.List;
public class TestBeanListHolder {
private List<TestBean> testBeans;
public List<TestBean> getTestBeans() {
return testBeans;
}
public void setTestBeans(List<TestBean> testBeans) {
this.testBeans = testBeans;
}
}
TestBeanHolder
package com.struts2test.beans;
import java.util.List;
import java.util.Map;
public class TestBeanHolder {
private Map<Integer, TestBean> testBeanMap;
private List<TestBean> testBeanList;
private Map<Integer, TestBeanListHolder> testBeanListMap;
public Map<Integer, TestBean> getTestBeanMap() {
return testBeanMap;
}
public void setTestBeanMap(Map<Integer, TestBean> testBeanMap) {
this.testBeanMap = testBeanMap;
}
public Map<Integer, TestBeanListHolder> getTestBeanListMap() {
return testBeanListMap;
}
public void setTestBeanListMap(
Map<Integer, TestBeanListHolder> testBeanListMap) {
this.testBeanListMap = testBeanListMap;
}
public List<TestBean> getTestBeanList() {
return testBeanList;
}
public void setTestBeanList(List<TestBean> testBeanList) {
this.testBeanList = testBeanList;
}
}
URL
http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanListMap[1].testBeans[0].value=somevalue
The url http://localhost:8080/Struts2Test/test?testBeanHolder.testBeanListMap[0][0].value=1 won't work because you are using wrong parameter name. Thus testBeanHolder.testBeanListMap[0][0].value is a name of the parameter that maps to the object which has a property of complex type (collection of collections). Struts2 can't handle such scenarios, . But you can wrap a second collection with an object and use a collection of objects. The name would change to testBeanHolder.testBeanListMap[0].object[0].value.
The expression testBeanHolder.testBeanListMap[0][0].value is not a valid OGNL expression.
See here for a complete reference of what is allowed.