I want to create a Map<Long, Enum< ? extends SomeInterface>. Which is the best option for me?
I tried this one
private Map<Long, Enum<? extends SomeInterface>[]> questionIdToanswersMapping = Collections.unmodifiableMap(Stream.of(
new SimpleEntry<>(QuestionEnum1.getQuestionId(), AnswerEnum1.values()),
new SimpleEntry<>(QuestionEnum2.getQuestionId(), AnswerEnum2.values()),
new SimpleEntry<>(QuestionEnum3.getQuestionId(), AnswerEnum3.values()),
new SimpleEntry<>(QuestionEnum4.getQuestionId(), AnswerEnum4.values()),
new SimpleEntry<>(QuestionEnum5.getQuestionId(), AnswerEnum5.values()))
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue())));
But it is giving error "cannot convert from Map<Object,Object> to Map<Long,Enum<? extends SomeEnum>[]>". I am new to this. Please help!
I need unmodifiable map of question Id to the corrosponding possible answers values. Possible answers are Enums
Possible Answers are wrapped like this :
public class RecognizedAnswers {
public enum AnswerEnum1 implements SomeInterface;
public enum Answer2 implements SomeInterface;
}
There is a small problem with naming I think:
You cannot extend one enum with another in java, use interface with desired method instead, like below
And below code is working fine:
#Test
public void test() {
Map<Long, Enum<? extends SomeEnum>[]> questionIdToanswersMapping = Collections.unmodifiableMap(Stream.of(
new AbstractMap.SimpleEntry<>(QuestionEnum1.A.getQuestionId(), AnswerEnum1.values()),
new AbstractMap.SimpleEntry<>(QuestionEnum1.B.getQuestionId(), AnswerEnum1.values()),
new AbstractMap.SimpleEntry<>(QuestionEnum1.C.getQuestionId(), AnswerEnum2.values()),
new AbstractMap.SimpleEntry<>(QuestionEnum1.D.getQuestionId(), AnswerEnum2.values())
)
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue())));
System.out.print(questionIdToanswersMapping.size());
}
enum QuestionEnum1 {
A, B, C, D;
Long getQuestionId() {
return (long) name().hashCode(); // my mocked values
}
}
interface SomeEnum {
}
enum AnswerEnum1 implements SomeEnum {
}
enum AnswerEnum2 implements SomeEnum {
}
I tried to replicate your example (since you obfuscated the enum types, I made up my own) and it appears to compile just fine:
enum SomeEnum { FOO, BAR }
private Map<Long, Enum<? extends SomeEnum>[]> exampleMap =
Collections.unmodifiableMap(Stream.of(
new SimpleEntry<>(1L, SomeEnum.values()))
.collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue)));
My guess is that you have either a missing parenthesis, or your QuestionEnum1.getQuestionId() returns an int rather than a long, and those things are confusing the compiler enough that it can't give a clear error message.
I'll note that the Stream API really isn't a clean way to construct a constant map. Simply building such a map "normally" with Map.put() will likely be simpler and easier to read, even if it requires a static {} block or a helper function. You can do even better with Guava's immutable collections, which could be used like so:
private final ImmutableMap<Long, Enum<? extends SomeEnum>[]> questionIdToanswersMapping =
ImmutableMap.builder()
.put(QuestionEnum1.getQuestionId(), AnswerEnum1.values())
.put(QuestionEnum2.getQuestionId(), AnswerEnum2.values())
.put(QuestionEnum3.getQuestionId(), AnswerEnum3.values())
.put(QuestionEnum4.getQuestionId(), AnswerEnum4.values())
.put(QuestionEnum5.getQuestionId(), AnswerEnum5.values())
.build();
Much clearer and easier to read (and write).
Related
I don't understand why the following code doesn't compile:
private ResponseEntity<JSendResponse> buildResponse(RequestModel requestModel,
RequestModelParamConverter paramConverter,
Supplier<String> xsdSupplier,
Supplier<String> xmlTemplateSupplier) {
return Optional.ofNullable(new RequestErrorHandler<>().validate(validator, requestModel))
.map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
.orElse(this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier));
}
Compile error:
orElse
(org.springframework.http.ResponseEntity<com.company.util.response.JSendFailResponse>)
in Optional cannot be applied to
(org.springframework.http.ResponseEntity<com.company.util.response.JSendResponse>)
While this code (which I think is logically the same code) does compile:
private ResponseEntity<JSendResponse> buildResponse(RequestModel requestModel,
RequestModelParamConverter paramConverter,
Supplier<String> xsdSupplier,
Supplier<String> xmlTemplateSupplier) {
JSendResponse validationErrors = new RequestErrorHandler<>().validate(validator, requestModel);
if(validationErrors == null) {
return this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier);
}
else
{
return new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST);
}
}
The problem seems to be that the RequestErrorHandler<>().validate method returns a class called JSendFailResponse if the validation fails. JSendFailResponse is a subclass of JSendResponse, which is what is ultimately returned. It seems like the lambda code is not able to understand that JSendFailResponse is a JSendResponse.
I can get it to compile if I cast validationErrors to a JSendResponse in the map lambda, but then I lose some of the fields on the JSendFailResponse.
EDIT: This code also fails to compile:
private ResponseEntity<? extends JSendResponse> buildResponse(RequestModel requestModel,
RequestModelParamConverter paramConverter,
Supplier<String> xsdSupplier,
Supplier<String> xmlTemplateSupplier) {
return Optional.ofNullable(new RequestErrorHandler<>().validate(validator, requestModel))
.map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
.orElse(this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier));
}
EDIT2: Here is a simplified example you can copy/paste into your IDE to see for yourself.
import java.util.*;
public class GemLamDemo {
public static void main(String... args) {
GemLamDemo gld = new GemLamDemo();
gld.getList(null);
}
public List<? extends TypeA> getList(TypeA ta) {
return Optional.ofNullable(ta)
.map(a -> new ArrayList<TypeA>(Arrays.asList(a)))
.orElse(new ArrayList<TypeB>(Arrays.asList(new TypeB())));
}
public class TypeA {
}
public class TypeB extends TypeA {
}
}
EDIT3: I was thinking I understood this issue based on the help I've received so far, but the following code compiles and works.
Optional.ofNullable(val1)
.map(a -> new TypeA())
.orElse(new TypeB());
So the issue does not seem to be that the map and the orElse must return the same type, it seems to be related to paramterization. So, map can emit TypeA and orElse can emit TypeB if its a subclass of TypeA. But they can not emit differing parameterized types of List. List<TypeA> and List<TypeB> don't seem to be considered subtypes of each other and now that I think about it, they aren't.
ResponseEntity<JSendResponse> is a different type than ResponseEntity<JSendFailResponse>. If I were returning plain JSendResponse and JSendFailResponse from the lambdas, that would probably work. But I'm not, I'm emitting different versions of ResponseEntity, which are not really related by hierarchy. So I guess it comes down to how Optional supports (or doesn't support) wildcard generics. I can't set the type of the Optional to ResponseEntity<? extends JSendResponse>, so I am limited to strict type hierarchies.
EDIT4:
The above example is incorrect because the types are switched from the original case. I think I get it now, thanks everybody.
The type emitted from map() is inferred as JSendFailResponse, but you’re offering a different type in orElse() and both types must agree.
Explicitly type to call to map() with a common type:
.<JSendResponse>map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
If you check the oracle documention : https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html,
The signature of .ofNullable() method is : public static <T> Optional<T> ofNullable(T value)
and orElse() : public T orElse(T other)
So the parameter on the both methods type is T and orElse() does not have <? extends T> as parameter they should both have T as type, so your method shall not work i guess,
you should try something this ( using your simplified example) :
public List<TypeA> getList(TypeA ta) {
ArrayList<TypeA> typeAinstance = new ArrayList<>();
return Optional.ofNullable(ta)
.map(a -> new ArrayList<TypeA>(Arrays.asList(a)))
.orElse(typeAinstance.getClass().cast(Arrays.asList(new TypeB())));
}
public class TypeA {
}
public class TypeB extends TypeA {
}
Hope this helps
I have the following classes
public class MyCustomFactory extends SomeOther3rdPartyFactory {
// Return our custom behaviour for the 'string' type
#Override
public StringType stringType() {
return new MyCustomStringType();
}
// Return our custom behaviour for the 'int' type
#Override
public IntType intType() {
return new MyCustomIntType();
}
// same for boolean, array, object etc
}
Now, for example, the custom type classes:
public class MyCustomStringType extends StringType {
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
if (prop.getSomeAttribute("attribute01")) {
this.doSomething();
this.doSomethingElse();
}
if (prop.getSomeAttribute("attribute02")) {
this.doSomethingYetAgain();
}
// other properties and actions
}
}
But each custom type class like the string one above might have exactly the same if (prop.getSomeAttribute("blah")) { // same thing; }
Suppose I was to add another attribute, is there a nice way I can avoid having to duplicate if statements in each custom type class that needs it? I can move each if statement to utility class but I still need to add the call to the method in the utility class. I think we can do better.
You can create Map<String, Consumer<MyCustomStringType>>, where the key is your attribute name and value is the method call.
public class MyCustomStringType extends StringType {
private final Map<String, Cosnumer<MyCustomStringType>> map = new HashMap<>();
{
map.put("attribute01", o -> {o.doSomething(); o.doSomethingElse();});
map.put("attribute02", MyCustomStringType::doSomethingYetAgain);
// other properties and actions
}
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
map.entrySet().stream()
.filter(entry -> prop.getSomeAttribute(entry.getKey()))
.forEach(entry -> entry.getValue().accept(MyCustomStringType.this));
}
}
Depending on how you initialise this class (and whether this map is always the same), you might be able to turn in into static final immutable map.
I would also recommend naming it better, but a lot here depends on your domain and what this map and loop actually do.
Been migrating over some legacy code and I came across this.
#Getter
#Setter
public class CollectedData
{
SkillResponse skills;
TrendingResponse storyMatch;
Map<String, String> slotData;
Map<String, String> slotDataSecondSource;
Boolean hasSlots;
Boolean hasSlotsSecondSource;
KnowledgeRequest request;
}
Since I've been using java 8 and accustomed to streams, I started to restructure this response class as ..
#Getter
#Setter
public class CollectedData
{
List<DataSupplierResponse> dataSupplierResponses;
Metadata metadata;
}
Where DataSupplierResponse was to be a defined interface like so..
public interface DataSupplierResponse<T>
{
DataSupplierType getDataSupplierType();
T getSupplierResponse();
}
Implementation Example:
public class DataSupplierResponseImpl implements DataSupplierResponse<TrendingResponse>
{
private TrendingResponse mTrendingResponse;
public DataSupplierResponseImpl(
TrendingResponse trendingResponse)
{
mTrendingResponse = trendingResponse;
}
#Override
public DataSupplierType getDataSupplierType()
{
return DataSupplierType.TRENDING_STORY;
}
#Override
public TrendingResponse getSupplierResponse()
{
return mTrendingResponse;
}
}
The goal is to run certain predicates depending on the CollectedData.
Optional<DataSupplierResponse> first = data.getDataSupplierResponses().stream()
.filter(res -> res.getDataSupplierType().equals(DataSupplierType.TRENDING_STORY))
.findFirst();
This would need a cast in order to get the right object. It returns Object
TrendingResponse match = first.get().getSupplierResponse();
Thus when I started refactoring, I assumed to solve this issue of data being available by creating the generic interface that returns different data. To make this code work, I would have to cast the return object of getSupplierResponse which defeats the purpose of using generics. I need to make this Data Carrier object as clean and beautiful as possible for my own sake. Any ideas how I should structure these classes, and/or how to use generics to solve this problem.
EDIT: I know the StackOverflow community likes to enforce objective, concrete answers but where else to go to for design questions?
You have to specify the List in CollectedData also with generics. E.g:
List<DataSupplierResponse> dataSupplierResponse;
should actually be:
List<DataSupplierResponse<YourType>> dataSupplierResponse;
where YourType corresponds to the type of the response. That is because when using a RawType (a generic class without actually specifiying a generic) all Generic information for that class is eliminated. That's why it is returning Objects and you have to manually cast it.
Unless used in other places, I'd get rid of the enumeration type DataSupplierType as the classes TrendingResponse (and others) already provide a discrimination criteria.
(Also keep in mind that enums are full classes)
The perfect response to this would have you implement a basic type for your response, e.g:
interface Response {
int getScore(); // implement in subclasses
String getName(); // implement in subclasses
}
class TrendingResponse implements Response {}
class SkillResponse implements Response {}
class OtherResponse implements Response {}
but this is not strictly necessary.
At this point just a generic wrapper class would be enough (no need to have a base interface and extend it for each type of response):
class DataSupplierResponse<T extends Response> {
private T t;
public DataSupplierResponse(final T t) {
this.t = t;
}
public T getSupplierResponse() {
return this.t;
}
}
This would allow you to call:
Optional<DataSupplierResponse<?>> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.findFirst();
first.ifPresent( o -> o.getSupplierResponse().getScore() );
or simply
Optional<?> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.map(r -> r::getSupplierResponse)
.findFirst();
Even without the base interface Response (which is useful only for defining common behavior in your responses), your class DataSupplierResponse<T> wouldn't need the enumeration type.
I have the ViewValue class defined as follows:
class ViewValue {
private Long id;
private Integer value;
private String description;
private View view;
private Double defaultFeeRate;
// getters and setters for all properties
}
Somewhere in my code i need to convert a list of ViewValue instances to a list containing values of id fields from corresponding ViewValue.
I do it using foreach loop:
List<Long> toIdsList(List<ViewValue> viewValues) {
List<Long> ids = new ArrayList<Long>();
for (ViewValue viewValue : viewValues) {
ids.add(viewValue.getId());
}
return ids;
}
Is there a better approach to this problem?
We can do it in a single line of code using java 8
List<Long> ids = viewValues.stream().map(ViewValue::getId).collect(Collectors.toList());
For more info : Java 8 - Streams
You could do it in a one-liner using Commons BeanUtils and Collections:
(why write your own code when others have done it for you?)
import org.apache.commons.beanutils.BeanToPropertyValueTransformer;
import org.apache.commons.collections.CollectionUtils;
...
List<Long> ids = (List<Long>) CollectionUtils.collect(viewValues,
new BeanToPropertyValueTransformer("id"));
Use google collections. Example:
Function<ViewValue, Long> transform = new Function<ViewValue, Long>() {
#Override
public Long apply(ViewValue from) {
return from.getId();
}
};
List<ViewValue> list = Lists.newArrayList();
List<Long> idsList = Lists.transform(list, transform);
UPDATE:
On Java 8 you don't need Guava. You can:
import com.example.ViewValue;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
Function<ViewValue, Long> transform = ViewValue::getId;
List<ViewValue> source = new ArrayList<>();
List<Long> result = source.stream().map(transform).collect(Collectors.toList());
Or just:
List<ViewValue> source= new ArrayList<>();
List<Long> result = source.stream().map(ViewValue::getId).collect(Collectors.toList());
NEXT UPDATE (The last one after Javaslang to Vavr name change):
Currently it's worth to mention about the solution with Javaslang library(http://www.javaslang.io/) Vavr library (http://www.vavr.io/). Let's assume that we have our list with genuine objects:
List<ViewValue> source = newArrayList(new ViewValue(1), new ViewValue(2), new ViewValue(2));
We could make transformation with List class from Javaslang library (on the long run the collect is not convenient):
List<Long> result = io.vavr.collection.List.ofAll(source).map(ViewValue::getId).toJavaList();
But you will see the power with only the Javaslang lists:
io.vavr.collection.List<ViewValue> source = javaslang.collection.List.of(new ViewValue(1), new ViewValue(2), new ViewValue(3));
io.vavr.collection.List<Long> res = source.map(ViewValue::getId);
I encourage to take a look available collections and new types on that library (I like especially the Try type). You will find the documentation under the following address: http://www.javaslang.io/javaslang-docs/ http://www.vavr.io/vavr-docs/.
PS. Due to the Oracle and the "Java" word within the name they had to change the library name from javaslang to something else. They had decided to Vavr.
EDIT: This answer is based on the idea that you'll need to do similar things for different entities and different properties elsewhere in your code. If you only need to convert the list of ViewValues to a list of Longs by ID, then stick with your original code. If you want a more reusable solution, however, read on...
I would declare an interface for the projection, e.g.
public interface Function<Arg,Result>
{
public Result apply(Arg arg);
}
Then you can write a single generic conversion method:
public <Source, Result> List<Result> convertAll(List<Source> source,
Function<Source, Result> projection)
{
ArrayList<Result> results = new ArrayList<Result>();
for (Source element : source)
{
results.add(projection.apply(element));
}
return results;
}
Then you can define simple projections like this:
private static final Function<ViewValue, Long> ID_PROJECTION =
new Function<ViewValue, Long>()
{
public Long apply(ViewValue x)
{
return x.getId();
}
};
And apply it just like this:
List<Long> ids = convertAll(values, ID_PROJECTION);
(Obviously using K&R bracing and longer lines makes the projection declaration a bit shorter :)
Frankly all of this would be a lot nicer with lambda expressions, but never mind...
I've implemented a small functional library for this usecase. One of the methods has this signature:
<T> List<T> mapToProperty(List<?> objectList, String property, Class<T> returnType)
Which takes the string and uses reflection to create a call to the property then it returns a List backed by the objectList where get and iterator implemented using this property call.
The mapToProperty functions is implemented in terms of a general map function that takes a Function as a mapper though, just as another post described. Very usefull.
I suggest you read up on basic functionl programming and in particular take a look at Functors (objects implementing a map function)
Edit: Reflection really doesn't have to be expensive. The JVM has improved a lot in this area. Just make sure to compile the invocation once and reuse it.
Edit2: Sample code
public class MapExample {
public static interface Function<A,R>
{
public R apply(A b);
}
public static <A,R> Function<A,R> compilePropertyMapper(Class<A> objectType, String property, Class<R> propertyType)
{
try {
final Method m = objectType.getMethod("get" + property.substring(0,1).toUpperCase() + property.substring(1));
if(!propertyType.isAssignableFrom(m.getReturnType()))
throw new IllegalArgumentException(
"Property "+property+" on class "+objectType.getSimpleName()+" is not a "+propertyType.getSimpleName()
);
return new Function<A,R>()
{
#SuppressWarnings("unchecked")
public R apply(A b)
{
try {
return (R)m.invoke(b);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
};
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T1,T2> List<T2> map(final List<T1> list, final Function<T1,T2> mapper)
{
return new AbstractList<T2>()
{
#Override
public T2 get(int index) {
return mapper.apply(list.get(index));
}
#Override
public int size() {
return list.size();
}
};
}
#SuppressWarnings("unchecked")
public static <T1,T2> List<T2> mapToProperty(List<T1> list, String property, Class<T2> propertyType)
{
if(list == null)
return null;
else if(list.isEmpty())
return Collections.emptyList();
return map(list,compilePropertyMapper((Class<T1>)list.get(0).getClass(), property, propertyType));
}
}
You could use a wrapper:
public class IdList impements List<Long>
{
private List<ViewValue> underlying;
pubic IdList(List<ViewValue> underying)
{
this.underlying = underying;
}
public Long get(int index)
{
return underlying.get(index).getId()
}
// other List methods
}
Though that's even more tedious work, it could improve performance.
You could also implement your and my solution generic-ly using reflection, but that would be very bad for performance.
There's no short and easy generic solution in Java, I'm afraid. In Groovy, you would simply use collect(), but I believe that involves reflection as well.
That depends on what you then do with the List<Long>, and the List<ViewValue>
For example you might get sufficient functionality from creating your own List implementation that wraps a List<ViewValue>, implementing iterator() with an iterator implementation that iterates over the ViewValues, returning the id.
You can populate a map from the properties of a list of objects (say id as key and some property as value) as below
Map<String, Integer> mapCount = list.stream().collect(Collectors.toMap(Object::get_id, Object::proprty));
I have a private instance
private final Map<Class<?>, ?> map;
Syntactically, this is correct. What I want to do is this.
public class User {
}
public class UserSubclass extends User {
}
public class Role {
}
map.put(User.class, new User()); // valid
map.put(User.class, new UserSubclass()); // valid
map.put(Role.class, new Role()); // valid
// But when I do the following I need to get an error
map.put(User.class, new Role(); // invalid, compiler error
How should I declare the Map?
How can I instantiate an object of HashMap to this Map?
No, a simple java.util.Map does not support this. It is statically typed, and what you ask for is basically dynamic typing of one parameter based on the runtime-type of another one.
However, the Guava class ClassToInstanceMap implements exactly what you want:
A map, each entry of which maps a Java raw type to an instance of that type. In addition to implementing Map, the additional type-safe operations putInstance(java.lang.Class<T>, T) and getInstance(java.lang.Class<T>) are available.
You cannot do this by default, but what you can do, is to create your own Generic Safe Map, which will work.
The GenericMap would look like this:
class GenericMap extends HashMap<Class<?>, Object> {
public <T> T putClassAndInstance(Class<T> c, T o){
return c.cast(super.put(c, o));
}
public <T> T getInstance(Class<T> c) {
return c.cast(super.get(c));
}
}
And can then be used like:
GenericMap map = new GenericMap();
map.putClassAndInstance(User.class, new User()); // valid
map.putClassAndInstance(User.class, new UserSubclass()); // valid
map.putClassAndInstance(Role.class, new Role()); // valid
map.putClassAndInstance(User.class, new Role()); // invalid, compiler error
This way, you don't have to create special methods for the User and Role, and still have the safety of not adding the wrong object for the wrong type.