JetBrains Academy: Generics and Reflection - Kamil-Jankowski/Learning-JAVA GitHub Wiki
Quality control system:
You are asked to create quality control system in a company that produces and packs Bakery, the snippet of main classes follows:
// These and its sublasses should pass quality check
class Bakery {}
class Cake extends Bakery {}
// And this and other stuff should not
class Paper {}
// These boxes are used to pack stuff
interface Box<T> {
void put(T item);
T get();
}
// Class you need to work on
class QualityControl {
public static boolean check(List<Box<? extends Bakery>> boxes) {
// Add implementation here
}
}
Implement check method in a way it would:
- Return true if all objects in all boxes belong to class Bakery or its subclasses or list contains no boxes
- Return false otherwise, including cases when Box is empty or List contains something that is not Box at all
The method shouldn't throw any exceptions.
class QualityControl {
public static boolean check(List<Box<? extends Bakery>> boxes) {
if (!(boxes.isEmpty())) {
for (int i = 0; i < boxes.size(); i++) {
if (boxes.get(i) instanceof Box) {
if (!(boxes.get(i).get() instanceof Bakery)) {
return false;
}
} else {
return false;
}
}
}
return true;
}
}
A talanted baker:
Pie company is looking for a talanted baker and you are invited to implement one. The baker's duty is to get orders for bakery and it's varieties and produces it. Class definition and method's backbone follows:
class Paper {}
class Bakery {}
class Cake extends Bakery {}
class ReflexiveBaker {
/**
* Create bakery of the provided class.
*
* @param order class of bakery to create
* @return bakery object
*/
public Object bake(Class order) {
// Add implementation here
}
}
The task is to redesign method signature types if needed and to add implementation. The bake method should conform to the following:
- Create objects of class Bakery or any subclass of it according to class argument
- Flag compile-time error if order argument is not Bakery or any subclass of it (e.g. if it is Paper or Object)
It's guaranteed that all subclasses of Bakery will have a public parameterless constructor.
/**
* Class to implement
*/
class ReflexiveBaker {
/**
* Create bakery of the provided class.
*
* @param order class of bakery to create
* @return bakery object
*/
public <T extends Bakery> T bake(Class<T> order) {
try {
return order.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError("Class could not be instantiated.", e);
}
}
}
Getting the type of comparator:
You need to implement method getComparatorType(Class) in ComparatorInspector class. The method should examine provided class and return Type object that corresponds to the type parameter that parameterizes Comparable interface the class implements. Consider the example:
class MyInt implements Comparable<Integer> {
// Implementation omitted
}
// Method to implement
Type type = ComparatorInspector.getComparatorType(MyInt.class);
System.out.println(type.getTypeName());
// prints: java.lang.Integer since MyInt implements Comparable with Integer parameter type
The method should:
- Return type parameter for Comparable interface class implements
- Return null if Comparable interface does not have type parameter
- Should not produce compile-time warnings
Additional requirements:
- Compile-time error should arise if class not implementing Comparable is provided as input value
- No 'rawtype' warnings should remain or be suppressed
- Method getComparatorType should be generic
You are free to correct method's type signature if needed.
/**
* Class to work with
*/
class ComparatorInspector {
/**
* Return Type variable that corresponds to the type parameterizing Comparator.
*
* @param clazz {@link Class} object, should be non null
* @return {@link Type} object or null if Comparable does not have type parameter
*/
public static <T> Type getComparatorType(Class<? extends Comparable<T>> clazz) {
Type[] genericInterfaces = clazz.getGenericInterfaces();
Type[] genericTypes = new Type[0];
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
String genInterface = ((ParameterizedType) genericInterface).getRawType().getTypeName();
if ("java.lang.Comparable".equals(genInterface)) {
genericTypes = ((ParameterizedType) genericInterface).getActualTypeArguments();
}
}
}
return genericTypes[0];
}
}