I need a solution, is my code structure correct, or is it a bad code structure?
The main problem is that compiler swears at the raw type.
Is this code structure bad? Why? Is it correct?
#NoRepositoryBean
public interface EntityRepository<E, ID extends Serializable> extends JpaRepository<E, ID> {
}
#NoRepositoryBean
public interface CatalogEntityRepository<C extends Catalog.Main, E extends CatalogEntity, ID extends Serializable>
extends EntityRepository<E, ID>, Catalog.Able<C> {
}
#Repository
public interface OrganizationEntityRepository extends CatalogEntityRepository<OrganizationCatalog, OrganizationEntity, Long> {
#Override
default OrganizationCatalog getCatalog() {
return Context.getApplicationContext().getBean(OrganizationCatalog.class);
}
}
Is this code structure bad? Why? Is it correct?
// Here I have some context class (CatalogEntityRepositoryContextImpl) that can find the repository which I need.
public interface EntityRepositoryContext<R extends EntityRepository> {
List<R> getAll();
Optional<R> find(String parentAlias);
default R get(String parentAlias) {
return find(parentAlias).orElseThrow(() -> {
throw new NoSuchEntityRepositoryException(parentAlias);
});
}
}
public interface CatalogEntityRepositoryContext<R extends CatalogEntityRepository>
extends EntityRepositoryContext<R> {
#Override
default Optional<R> find(String catalogAlias) {
return getAll().stream()
.filter(it -> Objects.equals(it.getCatalog().getAlias(), catalogAlias))
.findFirst();
}
#Override
default R get(String catalogAlias) {
return find(catalogAlias).orElseThrow(() -> {
throw new NoSuchCatalogEntityRepositoryException(catalogAlias);
});
}
}
#Component
#RequiredArgsConstructor
public class CatalogEntityRepositoryContextImpl
implements CatalogEntityRepositoryContext<CatalogEntityRepository> {
#Getter
private final List<CatalogEntityRepository> all;
}
And my main problem with raw type is: the code works, but I need confirmation from the guru that this code is not too bad, or give me some useful solutions, please.
I know raw type is bad practice. But I can't figure out how I can fix this in my situation.
public interface CatalogEntityService<C extends Catalog.Main, DS extends CatalogEntityDto.Single, DL extends CatalogEntityDto.Listable>
extends EntityService<DS, DL>, Catalog.Able<C> {
private CatalogEntityRepository getRepository() {
CatalogEntityRepositoryContextImpl repositoryContext = Context.getCatalogEntityRepositoryContext();
return repositoryContext.get(getCatalog().getAlias());
}
#Transactional
#Override
default Long create(DS dto) {
var repository = getRepository();
var mapper = getMapper();
var entity = mapper.mapToEntity(dto);
var savedEntity = repository.save(entity); // HERE IS THE RAW TYPE! "Unchecked call to 'save(S)' as a member of raw type 'app.unibas.core.catalog.repository.CatalogEntityRepository'"
return (Long) savedEntity.getId();
}
}
I have a list of implementations to SomeInterface
List<SomeInterface> listOfThingsThatImplementsSomeInterface
I want to extract a specific implementation from the list according to its class name
private SomeInterface getThisType(SomeInterfaceImpl myType) {
SomeInterfaceImpl impl = null
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (current instanceof myType) {
impl = current
break;
}
}
return impl;
}
Is that possible in Java? should I be using generics?
First you need the Class instance of the desired class (which you have, you mention "according to its class name"). You can get a Class instance from the class name using
Class<?> cls = SomeInterfaceImpl.class;
or if you have the class name as a String:
Class<?> cls = Class.forName("package.ClassName")
or from an instance using
SomeInterfaceImpl myType = ...;
Class<?> cls = myType.getClass()
Then you can call this method, assuming your have a List<SomeInterface> listOfThingsThatImplementsSomeInterface somewhere:
private SomeInterface getThisType(Class<?> myType) {
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (myType.isInstance(current)) {
return current;
}
}
return null; //nothing found
}
Suppose we have the desired implementation Class instance, (refer to #f1sh answer if the class is Class<?>), it can be done using Stream,
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
The key to match the type is using Class#isInstance.
Some points to note:
Make method return type generic so no cast is needed.
Class#cast can be used to convert the return type of the Stream.
Use Optional to handle case when no element matched.
Full example
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class FilterByClass {
List<SomeInterface> someInterfaceList = new ArrayList<>();
public static void main(String[] args) {
FilterByClass filterByClass = new FilterByClass();
filterByClass.someInterfaceList = List.of(new SomeInterfaceImplA(), new SomeInterfaceImplB(), new SomeInterfaceImplC());
System.out.println(filterByClass.getThisType(SomeInterfaceImplA.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplB.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplC.class).get().name());
}
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
public interface SomeInterface {
default String name() {
return this.getClass().getSimpleName();
}
}
public static class SomeInterfaceImplA implements SomeInterface { }
public static class SomeInterfaceImplB implements SomeInterface { }
public static class SomeInterfaceImplC implements SomeInterface { }
}
The method should take the class as parameter. Let's say your interface is T, you can receive a parameter of type Class<? extends T>
Then go through the list and check for an element with the same class
Here is an example that should work:
private static <T> Optional<T> getThisType(
List<T> listOfThingsThatImplementsInterfaceT,
Class<? extends T> klass) {
return listOfThingsThatImplementsInterfaceT.stream()
.filter(klass::isInstance)
.findFirst();
}
Test with a list of Serializable
List<Serializable> listOfThingsThatImplementsSerializable = Arrays.asList(
new Integer(1), new Float(2), new Double(3)
);
System.out.println(
getThisType(listOfThingsThatImplementsSerializable, Float.class)
);
Looking for the Float returns Optional[2.0]
The idea is make ExporParts function in Export Class works with any WebData derivative. To do that I need to know the T type class and it name.
The solution proposed works, but I have to write it manually. I was wondering if possible know the class name only with the current information about the type.
In the other hand, reflection is not an option. Too expensive.
Thanks.
Example
// Data gathered at runtime, may be other derivative class
WebData data = new BikeModel();
Webdata data2 = new FooModel();
BikeParser parser = new BikeParser();
FooParser parser2 = new FooParser();
// Should be BikeModel, FooModel
Class<?> returnedtype = parser.GetreturnType();
Class<?> returnedtype2 = parser2.GetreturnType();
// Exporter algorithms wrapper
Exporter exporter = new Exporter();
exporter.SetExporter("BikeExporter",returnedtype);
// Finally export data
exporter.ExportData(data);
// Works too
exporter.SetExporter("FooExporter",returnedtype2);
exporter.ExportData(data2);
Implementation:
public abstract class WebData { ... }
// Data models
public class BikeModel extends WebData { ... }
public class FooModel extends WebData { ... }
public interface IParser <T extends WebData>
{
T ParseData();
Class<T> GetReturnType();
}
// Concrete class
public class BikeParser implements IParser<BikeModel>
{
#Override
public BikeModel ParseData() { ... }
#Override
public Class<BikeModel> GetReturnType()
{
return BikeModel.class;
}
// interface to export diferent types of data
// BikeModel, FooModel, etc.
public interface IExporter<T extends WebData>
{
void ExporParts(T data);
}
// Concrete Exporters
public class BikeExporter implements IExporter<BikeModel> { ... }
public class FooExporter implements IExporter<FooModel> { ... }
public class Exporter
{
private IExporter exporter;
public void SetExporter(String name, Class<T extends WebData> type)
{
exporter = ExporterFactory.GetExporter(name,type)
}
public <T extends WebData> void ExporParts(T data)
{
Class<T> c = (Class<T>) data.getClass();
exporter.ExporParts(c.cast(data));
}
}
I think you're just looking for a class literal:
#Override
public Class<BikeModel> GetReturnType()
{
return BikeModel.class;
}
I want to mock a generic interface:
public interface IModel<T, S> {
public S classify(T entity);
}
This interface is sub-classed by 3 concrete classes: TextModel, ImageModel, ScoringModel. Each of these concrete classes have different T and S parameters.
I wrote a generic method that receives the concrete model class as an argument and generates a mocked version of the model:
private <T extends IModel<?, ?>> T mockModel(Class<T> modelClass) {
return new MockUp<T>() {
#Mock public Object classify(Object entity) { return null; }
}.getMockInstance();
}
I know that IModel::classify has generic types for both its input and output, but I haven't found a way to use the actual generic method within the mockup.
When calling this method I get an IllegalArgumentException:
java.lang.IllegalArgumentException: Value of type com.classificationmanager.model.$Impl_IModel incompatible with return type com.classificationmanager.model.TextModel of com.classificationmanager.model.TextModelFactory#createModel(com.classificationmanager.model.ModelDescriptor)
at com.classificationmanager.model.ModelFetcherTest$5.(ModelFetcherTest.java:110)
at com.classificationmanager.model.ModelFetcherTest.mockAllFactories(ModelFetcherTest.java:109) ....... (spared you the rest)
I thought that getting and returning an Object instead of T and S was the problem, but I get the same exception when removing the mocked method and just mocking the class:
private <T extends IModel<?, ?>> T mockModel(Class<T> modelClass) {
return new MockUp<T>() {
}.getMockInstance();
}
I could do a switch-case and return a concrete class but that would just be nasty.
Any workaround involving the Expectations API would also work for me.
10x
Maybe the following examples can help (although I still don't understand the question - probable case of the XY problem).
public final class ExampleTest {
public interface IModel<T, S> { S classify(T entity); }
static class TextModel implements IModel<Integer, String> {
#Override public String classify(Integer entity) { return "test"; }
}
static class ImageModel implements IModel<String, Image> {
#Override public Image classify(String entity) { return null; }
}
#Test
public void createNonMockedInstanceForAnyModelClass() {
IModel<Integer, String> m1 = mockModel(TextModel.class);
String s = m1.classify(123);
IModel<String, Image> m2 = mockModel(ImageModel.class);
Image img = m2.classify("test");
assertEquals("test", s);
assertNull(img);
}
<T extends IModel<?, ?>> T mockModel(Class<T> modelClass) {
// Or use newUninitializedInstance in case the model class doesn't
// have a no-args constructor.
return Deencapsulation.newInstance(modelClass);
}
#Test
public void mockAllModelImplementationClassesAndInstances(
#Capturing IModel<?, ?> anyModel
) {
IModel<Integer, String> m = new TextModel();
String s = m.classify(123);
assertNull(s);
}
}
I have a fairly complicated structure, and it is not working as intended. This is what I did:
public interface ResultServiceHolder {
<M, ID extends Serializable, BO extends BusinessObject<M, ID>> ResultService<M, ID, BO> getService();
}
public enum ResultTypes implements ResultServiceHolder {
RESULT_TYPE_ONE {
#Override
public ResultOneService getService() { //unchecked conversion?
return serviceInitializer.getResultOneService();
}
},
RESULT_TYPE_TWO {
#Override
public ResultTwoService getService() { //unchecked conversion?
return serviceInitializer.getResultTwoService();
}
},
RESULT_TYPE_THREE {
#Override
public ResultThreeService getService() { //unchecked conversion?
return serviceInitializer.getResultThreeService();
}
};
protected ServiceInitializer serviceInitializer;
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
#Component
public static class ServiceInitializer {
#Autowired
private ResultOneService resultOneService;
#Autowired
private ResultTwoService resultTwoService;
#Autowired
private ResultThreeService resultThreeService;
#PostConstruct
public void init() {
for(ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
//getters
}
}
The purpose was to generalize the call based on enums, and rather, just be able to iterate on the array of enums.
for(ResultServiceHolder resultServiceHolder : ResultTypes.values()) {
if(resultServiceHolder.equals(post.getPostResultTypeCode())) {
return resultServiceHolder.getService().createResultSearchCriteriaResponse(postId);
}
}
And this is working fine and dandy. However, if I'd say
ResultTypes.RESULT_TYPE_ONE.getService().getRepository()
Then it is a BaseRepository<Object, Serializable> rather than a BaseRepository<ResultTypeOne, Long>. The method resultTypeHolder.getService() gives back ResultService<M, ID, BO>, but in the end, it becomes Object andSerializable.
What am I doing wrong? How can I retain the generic parameter types?
I'd like to add that yes, I do realize the problem is somewhere with the unchecked casting. But the services are defined as
public interface ResultTypeOneService
extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> {
}
And I don't know why the types are not inferred.
EDIT: Technically, it works if I explicitly infer them:
ResultTypes.RESULT_TYPE_ONE.<ResultTypeOne, Long, ResultTypeOneBO>getService().getRepository()
But it ought to be automatic, why is it not working automatically? Am I supposed to provide it with some kind of object that contains the type? Why is the return type not enough for that?
EDIT2: The superclass of the ResultTypeOne is
#SuppressWarnings("serial")
#EntityListeners(EntityListener.class)
#MappedSuperclass
public abstract class EntityBase implements Serializable {
But it is not mapped anywhere in the bounds.
EDIT3: A big thank you to #Radiodef! The theoretic solution ended up to be the following, and would work perfectly fine:
public interface ResultServiceHolder<M, ID extends Serializable, BO extends BusinessObject<M, ID>> {
ResultService<M, ID, BO> getService();
}
public abstract class ResultTypes<M, ID extends Serializable, BO extends BusinessObject<M, ID>>
implements ResultServiceHolder<M, ID, BO> {
public static ResultTypes<?, ?, ?>[] values() {
return new ResultTypes<?, ?, ?>[] {RESULT_ONE, RESULT_TWO, RESULT_THREE};
}
public static final ResultTypes<ResultOne, Long, ResultOneBO> RESULT_ONE = new ResultTypes<ResultOne, Long, ResultOneBO>("Result One") {
#Override
public ResultOneService getService() {
return serviceInitializer.resultOneService;
}
};
public static final ResultTypes<ResultTwo, Long, ResultTwoBO> RESULT_TWO = new ResultTypes<ResultTwo, Long, ResultTwoBO>("Result Two") {
#Override
public ResultTwoService getService() {
return serviceInitializer.resultTwoService;
}
};
public static final ResultTypes<ResultThree, Long, ResultThreeBO> RESULT_THREE = new ResultTypes<ResultThree, Long, ResultThreeBO>("Result Three") {
#Override
public ResultThreeService getService() {
return serviceInitializer.resultThreeService;
}
};
protected String name;
protected ServiceInitializer serviceInitializer;
private ResultTypes(String name) {
this.name = name;
}
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
#Component
static class ServiceInitializer {
#Autowired
private ResultOneService resultOneService;
#Autowired
private ResultTwoService resultTwoService;
#Autowired
private ResultThreeService resultThreeService;
#PostConstruct
public void init() {
for (ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
}
}
I think because of how lengthy the solution becomes, I'll stick with the enum approach, and just accept this loss of bounds. I lose more by having to add my own values() implementation than I gain from enforcing these bounds. However, this is an interesting theoretical exercise, and thank you again for your help.
Okay, first you need to understand why what you're doing is probably not what you think it's doing. Let's look at a simpler example.
interface Face {
<T> List<T> get();
}
What you have there is a generic method, get. A generic method's type parameter depends on what is supplied by the call site. So for example like this:
Face f = ...;
// this call site dictates T to be Number
List<Number> l = f.<Number>get();
When you override it like
class Impl implements Face {
#Override
public List<String> get() { return ...; }
}
This is something you are able to do (only because of erasure) but you probably shouldn't. It's only allowed for backwards compatibility to non-generic code. You should listen to the warning and not do it. Doing it means that for example I can still come along and dictate it to return something else:
Face f = new Impl();
// now I've caused heap pollution because you
// actually returned to me a List<String>
List<Number> l = f.<Number>get();
This is why there is an unchecked conversion.
What you probably meant is to use a generic interface declaration:
interface Face<T> {
List<T> get();
}
Now the argument to T depends on the type of the object reference.
Face<Number> f = ...;
// get must return List<Number>
List<Number> l = f.get();
We can implement it like
class Impl implements Face<String> {
#Override
public List<String> get() { return ...; }
}
Additionally, you cannot access covariant return types on an enum. When you override methods on an enum constant, its class is anonymous. An anonymous class has no name and cannot be referred to. Therefore the programmer cannot know its covariant return type to use it. Furthermore, an enum cannot declare generic type parameters. So what you are wanting to do is simply impossible with enum.
You can use a class with public static final instances to simulate a generic enum:
public abstract class SimEnum<T> implements Face<T> {
public static final SimEnum<Number> A = new SimEnum<Number>() {
#Override
public List<Number> get() { return ...; }
};
public static final SimEnum<String> B = new SimEnum<String>() {
#Override
public List<String> get() { return ...; }
};
private SimEnum() {}
public static SumEnum<?>[] values() {
return new SimEnum<?>[] { A, B };
}
}
Otherwise you need to drastically change your idea.
Maybe use an interface/abstract class instead of an enum?
Enums cannot have type parameters but classes and interfaces can.
For example...
Interfaces
Entity.java
The "thing" interface...
import java.io.Serializable;
public interface Entity<K extends Serializable> {
// TODO: Put entity type things here!
// for example, things like "K getId();"
// You may want an abstract base class for this interface that all Entitys extend
}
Repository.java
Does CRUD stuff with things...
import java.io.Serializable;
public interface Repository<K extends Serializable, V extends Entity<K>> {
V getValue(K key);
// Other CRUD stuff
}
Service.java
A Service is responsible for doing stuff with things...
public interface Service<K, V> {
// Could have an abstract service class that has a repository and implements this for you...
V get(K key);
// Other "generic service" type stuff
}
Solid Classes
Entity1.java
Solid base class with String key...
public class Entity1 implements Entity<String> {
// TODO implement Entity stuff...
}
Entity2.java
Solid base class with Integer key...
public class Entity2 implements Entity<Integer> {
// TODO implement methods...
}
Entity1Service.java
Solid Entity1 Service
public class Entity1Service implements Service<String, Entity1> {
// Would not have to implement this if you extended an abstract base Service class
#Override
public Entity1 get(String key) {
return null;
}
}
Entity2Service.java
Solid Entity2 Service
public class Entity2Service implements Service<Integer, Entity2> {
// Wouldn't need this if you had abstract Service class either...
#Override
public Entity2 get(Integer key) {
return null;
}
}
ServiceHolder.java
Not an enum, but an interface - you could add methods to set the "service" from spring or something here...
import java.io.Serializable;
public abstract class ServiceHolder<K extends Serializable, V, S extends Service<K, V>> {
public static final ServiceHolder<String, Entity1, Entity1Service> ENTITY_1_SERVICE = new ServiceHolder<String, Entity1, Entity1Service>() {};
public static final ServiceHolder<Integer, Entity2, Entity2Service> ENTITY_2_SERVICE = new ServiceHolder<Integer, Entity2, Entity2Service>() {};
private S service;
private ServiceHolder() {
}
public S getService() {
return service;
}
public void setService(S service) {
this.service = service;
}
}
The interesting bit
I think this is the sort of thing you wanted, please let me know if I misunderstood...
public class PleaseCompile {
public static void main(String[] args) {
Entity1 solid1 = ServiceHolder.ENTITY_1_SERVICE.getService().get("[KEY]");
Entity2 solid2 = ServiceHolder.ENTITY_2_SERVICE.getService().get(42);
...
}
}
Hope this helps...
You cannot do what you want to do.
List<String> and List<Integer> face type erasure at runtime.
And so do your enum-mapped getService() functions.
Everything related to types for generics is validated at compile-time.