I'm building an application using Spring webmvc + data jpa with Java 8. I have entities inheritance like:
public class BaseEntity {...}
public class Report extends BaseEntity {...}
public class BlahBlah extends BaseEntity {...}
On the other hand, to enable CRUD operations on the entities, some repository interfaces are created as below:
/**
* Read-only repository.
* See reference article
*/
#NoRepositoryBean
public interface BaseRepository<T extends BaseEntity> extends Repository<T, Long> {
T findOne(Long id);
Iterable<T> findAll();
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pagable);
}
And for each inherited entity class there's a repository interface:
public interface ReportRepository extends BaseRepository<Report>, PagingAndSortingRepository<Report, Long> { }
The client code looks like this: (ReportController.java)
Report entity = reportRepo.findOne(id);
The application compiles and runs as we expected in eclipse. However when I try to package it using maven, there're several compilation errors, which are all similar to:
ReportController.java:[66,43] reference to findOne is ambiguous
both method findOne(ID) in org.springframework.data.repository.CrudRepository
and method findOne(java.lang.Long) in com.myapp.repositories.BaseRepository
match
I don't quite understand the problem here. Yes, there's Type Erasure. But I also remember that if class BaseRepository<T> extends Repository<T, Long>, then BaseRepository will carry some information about the Type Argument passed to Repository. Isn't it?
If no, then how does JDK provides methods java.lang.Class.getGenericSuperclass() and java.lang.reflect.ParameterizedType.getActualTypeArguments()?
If yes, then there should not be ambiguous methods because both interfaces have the same method findOne(Long)...
Any explaination? Thanks.
Updated:
For you to reproduce the issue with ease, I created a tiny project at https://github.com/guogin/problemapp. Please checkout.
OK, I'm back to answer the question myself.
Inspired by comment from Didier L, I tried to look up in the JLS. And now I have the answer.
First, jls-§9.4.1 states:
An interface I inherits from its direct superinterfaces all abstract and default methods m for which all of the following are true:
m is a member of a direct superinterface, J, of I.
No method declared in I has a signature that is a subsignature (§8.4.2) of the signature of m.
There exists no method m' that is a member of a direct superinterface, J', of I (m distinct from m', J distinct from J'), such that m' overrides from J' the declaration of the method m.
In my sample code:
I = ReportRepository
J1 = BaseRepository<Report>
m1 = findOne(Long) from J1
J2 = PagingAndSortingRepository<Report, Long>
m2 = findOne(Long) from J2
Because J2 is not superinterface of J1 - So I actually inherits both m1 and m2 - that is to say, one findOne(Long) from BaseRepository<Report>, the other from PagingAndSortingRepository<Report, Long>.
The interface ReportRepository is itself syntax correct because both methods are inherit from super interfaces:
jls-§9.4
It is a compile-time error for the body of an interface to declare, explicitly or implicitly, two methods with override-equivalent signatures (§8.4.2). However, an interface may inherit several abstract methods with such signatures (§9.4.1).
And no clashes occurs.
In my example, the compilation error actually occurs at the caller method. So I further refer to jls-§15.12.2.5: Choosing the Most Specific Method.
It turns out that, when compiling the code ReportController especially the call to ReportRepository.findOne(Long), the compiler must find the more specific method between m1 and m2. But then it find both are equally specific. Thus a compile-time error of 'ambiguous method call' occurs. That's what happened.
It turns out the eclipse compilation is not as standard as maven.
Related
I have two REST services using Spring Boot running on two different servers. I am using REST Template for this communication.
There are some models that are shared by these two services. All these models are of type 'IDataToTransferred' .
'IDataToTransferred' is a marker Interface implemented by various Model Beans.
I need to write a common logic for passing a list of these models between these REST services.
Hence I wrote a logic which uses parameters
List<? extends IDataToTransferred> from Sender service to Receiver Service.
Update: With Some Code
IDataToTransferred.java is a marker Interface
DataToBeSent.java
DataToBeSent Implements IDataToTransferred{
//Simple Pojo
}
SenderService.java
sendData(List<? extends IDataToTransferred> uploadDataObjectList){
//Some Code with REST Template
//restTemplate.postForEntity
}
IDataToTransferred Interface is shared between communicating webservices.
DataToBeReceived.java
DataToBeReceived Implements IDataToTransferred{
//Simple Pojo
}
ReceiverService.java
receiveData(List<? extends IDataToTransferred> uploadDataObjectList){
//Some Code to convert uploadDataObjectList to DataToBeReceived
}
Note In REST service I was always getting 415 error. Unsupported Media type. when I use the same List<? extends IDataToTransferred> on Receiver.
When I changed this to List<? super IDataToTransferred> on Receiver side, now it works, I am guessing because of Producer extends Consumer super rules.
But the problem is that now I can't typecast to the IDataToTransferred type on Receiver Side. Inside the list I am getting all linkedHashmap, the json got converted to linked HashMap between these services.
How can I get DataToBeReceived class object in ReceiverService?
For simplicity sake I have removed Controllers. Assume that they have the same signature as the services.
If I had known better terms to search, I would have found answer before Posting. But alas.
In any case I found the answer in stackoverflow page here together with a this blog ofcourse.
The examples are with abstract classes. I have used with interfaces.
As mentioned in the link. I Introduced below annotation in the marker interface IDataToTransferred:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
#Type(value = DataToBeSent.class, name = "datatransfer")})
The property type is introduced in the bean DataToBeSent as a property. This type param is used as information for conversion into implementing type from interface type. One can use a different variable than one named "type". In JsonSubTypes annotation , we mention the classes that are implementing this interface.
DataToBeSent Implements IDataToTransferred{
//Simple Pojo
// Some Properties with getter and setter
String type = "datatransfer";
//with getter and setter
}
The same exercise needs to be implemented on the Receiver Side also. Hence, we will have annotation as below:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
#Type(value = DataToBeReceived.class, name = "datatransfer")})
Here, we have DataToBeReceived class as implementing the IDataToTransferred interface. Ofcourse you need to add type as property to DataToBeReceived class also as below:
DataToBeReceived Implements IDataToTransferred{
//Simple Pojo
// Some Properties with getter and setter
String type = "datatransfer";
//with getter and setter
}
Hope this helps.
I have a CRUD repository from this example of Spring Data. I'm trying to add custom permission evaluation, but in my implementation of PermissionEvalutor, targetDomainObject is always null.
ItemRepository
#PreAuthorize("hasRole('ROLE_USER')")
public interface ItemRepository extends CrudRepository<Item, Long> {
#PreAuthorize("hasPermission(#entity, 'DELETE')")
<S extends Item> S save(S entity);
#PreAuthorize("hasRole('ROLE_ADMIN')")
void delete(Long id);
}
Following the suggestions in the answers to this question of making the interface and implementation parameter names to match, I've tried changing entity by item in both the expression and the method parameter. I'm not sure what implementation should match against what interface here, so I'm guessing is SimpleJpaRepository against ItemRepository/CrudRepository. Anyway, it doesn't work, targetDomainObject is always null. Same for targetId in the other method.
Debugging MethodSecurityEvaluationContext.lookupVariable shows that args.length = 0, inside the method addArgumentsAsVariables(), that then logs Unable to resolve method parameter names for method: public abstract xx.xxx.Item xx.xxx.ItemRepository.save(xx.xxx.Item). Debug symbol information is required if you are using parameter names in expressions.. At lookupVariable, everything is null.
Is the debug symbol not #? What am I doing wrong?
Haven't looked in the actual code, but judging from what you write about the debug information, Spring isn't able to find the parameter names, probably since the come from interfaces and those aren't included in the bytecode by default.
Try adding a -parameters compiler flag. Also see this answer for a probably similar problem: https://stackoverflow.com/a/40787280
As Bloch states in Item 3 ("Enforce the singleton property with a private constructor or an enum type") of Effective Java 2nd Edition, a single-element enum type is the best way to implement a singleton. Unfortunately the old private constructor pattern is still very widespread and entrenched, to the point that many developers don't understand what I'm doing when I create enum singletons.
A simple // Enum Singleton comment above the class declaration helps, but it still leaves open the possibility that another programmer could come along later and add a second constant to the enum, breaking the singleton property. For all the problems that the private constructor approach has, in my opinion it is somewhat more self-documenting than an enum singleton.
I think what I need is an annotation which both states that the enum type is a singleton and ensures at compile-time that only one constant is ever added to the enum. Something like this:
#EnumSingleton // Annotation complains if > 1 enum element on EnumSingleton
public enum EnumSingleton {
INSTANCE;
}
Has anyone run across such an annotation for standard Java in public libraries anywhere? Or is what I'm asking for impossible under Java's current annotation system?
UPDATE
One workaround I'm using, at least until I decide to actually bother with rolling my own annotations, is to put #SuppressWarnings("UnusedDeclaration") directly in front of the INSTANCE field. It does a decent job of making the code look distinct from a straightforward enum type.
You can use something like this -
public class SingletonClass {
private SingletonClass() {
// block external instantiation
}
public static enum SingletonFactory {
INSTANCE {
public SingletonClass getInstance() {
return instance;
}
};
private static SingletonClass instance = new SingletonClass();
private SingletonFactory() {
}
public abstract SingletonClass getInstance();
}
}
And you can access in some other class as -
SingletonClass.SingletonFactory.INSTANCE.getInstance();
I'm not aware of such an annotation in public java libraries, but you can define yourself such a compile time annotation to be used for your projects. Of course, you need to write an annotation processor for it and invoke somehow APT (with ant or maven) to check your #EnumSingleton annoted enums at compile time for the intended structure.
Here is a resource on how to write and use compile time annotations.
I'm trying to send events and do this generically. I mean - create one abstract base DAO class with generic type and fire the event from its method. This should work for all descendants. This works if I define the exact type, but doesn't - if I use generics. What I mean:
AbstractDAO (with generics - doesn't fire the event):
public abstract class AbstractDAO<T extends Persistable> implements Serializable {
#Inject #PostSaveEvent Event<T> postSaveEvent;
public T saveOrUpdate(T object) throws DatabaseException {
T obj = em.merge(object);
postSaveEvent.fire(obj);
}
}
AbstractDAO (no generics, just simple class cast - fires the event):
public abstract class AbstractDAO<T extends Persistable> implements Serializable {
#Inject #PostSaveEvent Event<Polis> postSaveEvent;
public T saveOrUpdate(T object) throws DatabaseException {
T obj = em.merge(object);
postSaveEvent.fire((Polis)obj);
}
}
PolisDAO class, which extends AbstractDAO and defines the generic type:
#Stateless
#Named
#PolisType
public class PolisDAO extends AbstractDAO<Polis> {
// some methods (saveOrUpdate is not overriden!)
}
My observer class:
#Stateless
#Named
public class ProlongationService {
public void attachProlongationToPolisOnSave(#Observes #PostSaveEvent Polis polis) throws DatabaseException {
// ... DO smth with polis object. This is NOT called in the first case and called in the second
}
THis is very strange for me, as "fire()" method for CDI event should define the event type on runtime, not during compilation or deployment... When I debug, I see, that
postSaveEvent.fire(obj);
from the first sample operates exactly with Polis entity. But no event is fired nevertheless...
Upd. I tried the base generic class, but no luck:
#Inject #PostSaveEvent Event<Persistable> postSaveEvent;
Thanks.
This should, in theory, work, however in practice inspecting the type of generic objects at runtime with Java Reflection is, at times, impossible. This is due to type erasure. IIRC the type of the concrete sub class isn't erased, so it should be possible to reconnect this, but I guess the implementation isn't doing this right now.
File this as a bug in the http://issues.jboss.org/browse/WELD issue tracker (if you are using Weld), with the classes you provide as an example and we can try to fix it.
To work around, try injecting the event into the concrete subclass, and passing it as an argument, or using an accessor method, to get it into the abstract super class.
I'm relatively new to Spring and I've got myself dug in a hole. I'm trying to model motor cars. Each model has it's own builder object, and I have a BuilderFactory that returns the correct builder based upon user selection from a web-app.
So I'm looking for suggestions on how to approach this problem where I need to create a number of individual vehicles, but I don't know what type of vehicle I'm going to need until run-time, and each vehicle needs to be unique to the user.
What I've got at the moment is shown below. The problem I have at the moment is that because the individual builders are singletons so are the individual vehicles. I need them
to be prototypes. I know it all looks pretty horrible so I'm sure there must be a better way of doing this.
The top level from the web-app looks like;
Vehicle vehicle = vehicleBuilderFactory.getBuilder(platform).build();
My vehicleBuilderFactory looks like this;
#Service
public class VehicleBuilderFactory {
#Autowired
Discovery3Builder discovery3Builder;
#Autowired
Discovery4Builder discovery4Builder;
// Lots of #Autowired statements here.
#Autowired
FreeLander2010Builder freeLander2010Builder;
public VehicleBuilder getBuilder(Platform platform) {
switch (platform.getId()) {
case 1: return discovery3Builder;
case 2: return discovery4Builder;
// Lots of case statements here
case 44: return freeLander2010Builder;
default: return null;
}
}
}
which itself looks pretty horrible. Each individual builder looks like;
#Service
public class DefenderBuilder implements VehicleBuilder {
#Autowired
Defender defender;
// Loads of Defender specific setters ommitted
#Override
public Vehicle build() {
return defender;
}
}
and finally the individual vehicle
#Service
#Scope("prototype")
public class Defender extends Vehicle {
}
The main problem now, is that because the builders are singletons, so are the vehicles, and
I need them to be prototypes, because User A's Defender is different to user B's Defender.
You can use Spring's ObjectFactory to have it service up prototype scoped beans from a singleton scoped bean. The usage is pretty straightforward:
#Component
class DefenderBuilder implement VechicleBuilder {
#Autowired
ObjectFactory<Defender> defenderFactory;
Defender build() {
return defenderFactory.getObject()
}
}
#Component
#Scope("prototype")
class Defender {
}
This returns a new Defender on each call to defenderFactory.getObject()
Without reading too much into the detail you say you want to produce Prototype beans from a singleton possibly with a look up in the IoC container.
Section 3.4.6.1 Lookup method injection of the Spring documentation describes how this can be done without losing the Inversion of Control i.e. without your beans knowing about the bean store.
I have made use of the ServiceLocatorFactoryBean to solve a similar problem before. The class level Javadoc is excellent and contains some clear examples.
Two things:
1) You can use proxy in order to hold narrower scope from wider scope(e.g prototype from singleton)
All you need is to define the prototype component with the relevant scope and proxyMode
You can read about scoped proxy here.
2) Another thing that I have noticed is that you plan to use multiple autowired annotation.
note that you can use autowire on a list of interface and it will autowire all components that implements this interface as discussed here.
Moreover you can add a platform id to the VehicleBuilder interface and then generate a map in the constructor e.g:
Map<Integer, VehicleBuilder> vehicleBuilders;
#Autowired
public VehicleBuilderFactory(List<VehicleBuilder> vehicleBuilders) {
this.vehicleBuilders = vehicleBuilders.stream()
.collect(Collectors(x -> x.getPlatformId(), x -> x));
}
in that way you can avoid the switch case.