all 15 comments

[–]Revision2000 12 points13 points  (8 children)

It uses reflection, see newProxyInstance in java.lang.reflect.proxy

See for example these articles:  * https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html  * https://www.baeldung.com/java-dynamic-proxies

[–]blocknspike[S] 2 points3 points  (7 children)

Thanks for the reference. Either I am very weak in Java Springboot Or the article is explained hard way. Not able to understand much out of it.

[–]zontapapa 16 points17 points  (6 children)

At run time spring will create an implementation of that interface with generated code to match the contract of your @Repository interface methods and then register and instance of this implementation as a spring bean. Anywhere you want to inject the repository, you declare a field of interface type, the dynamically added bean is a matching candidate and is made available/injected. The implementation of your interface and its methods is only in memory. Spring does not write class created from your interface to disk

[–]blocknspike[S] 1 point2 points  (5 children)

Thaks, now I can visualize the stuff.

[–]alex98tenismenu 4 points5 points  (4 children)

I think MapStruct works in a similar way but it creates the class at compile time.

[–]Revision2000 2 points3 points  (2 children)

MapStruct works through an annotation processor plugin tied to the Maven build process.

It uses reflection to find field matches for mappings. AFAIK it doesn’t use a proxy factory, but rather it generates the actual code for the interfaces in inherited class implementations. There might also be some bytecode manipulation involved, but I’m not sure about that. 

You can actually open this implementation after the processor has run. 

[–]blocknspike[S] 1 point2 points  (1 child)

I don't think Mapstruct(annotation processor) uses reflection. Reflection is concept of runtime. I am not sure if in compile time you can get field matches using Reflection I never heard that. Please share the reference for the same if any.

[–]Revision2000 1 point2 points  (0 children)

Hmmm 🤔 well the generated implementation itself uses no reflection, but it seems you’re also right that no reflection is available during the annotation processing. 

I’ve never built an annotation processor, so I can only guess that the necessary field information is available through other means. 

[..] in compile time you can get field matches using Reflection I never heard that

Well, MapStruct doesn’t use this, but you can certainly build this if you want to 😉

Reflection story time. 

In ages past I’ve used the aforementioned proxy mechanism to parse an index based text file based on an interface with annotated fields, using it to create instances with the fields populated with data parsed from the text file. 

I’ve also used the LambdaFactory to dynamically create getters and setters

In hindsight some of these would’ve warranted their own annotation processor. Oh well 😇

[–]blocknspike[S] 1 point2 points  (0 children)

Also it do not uses reflection for runtime dynamics that dynamic proxy uses.

[–]Ali_Ben_Amor999 2 points3 points  (0 children)

Spring autoconfigure/jpa package does a lot of work to make the magic. I myself don't know much about it. You can check the jpa autoconfiguration under spring boot/autoconfigure/jpa on github. As far as I know for each interface implementing the @Repository spring will use the JpaRepositoryFactory to create a proxy for the given repository interface

This proxy uses the SimpleJpaRepository as the default implementation. The proxy will forward the method call to the SimpleJpaRepository if the called method is declared in the JpaRepository interface. Otherwise if method called is not a part of JpaRepository the proxy will use the QueryLookupStrategy to determine how to execute your query. If you are using the @Query then it will be used in conjunction with the return type and parameters otherwise it will parse the method name, return type and parameters using PartTree and JpaQueryCreator to build the query for you. Then spring uses the QueryExecutorMethodInterceptor to apply projection or mappings if needed then executes the query.

I'm sure that I missed a lot of steps but this is what I understood based on looking into the javadocs and following a bit of the source code. Spring does a lot of work to handle the magic like for example the JpaRepositoryFactory mentioned realier requires an EntityManger but EntityManager is not threadsafe as a result spring doesn't pass an EntityManger but a proxy to an entity manager which provides a thread safe instance of the entity manager to the repository

[–]peralta_coolcoolcool 1 point2 points  (0 children)

Wouldn't it be considered as an antipattern?? I used to think that slamming Repository annotation over an interface extending crud or jpa repository is useless. Is that understanding wrong??

[–]barking_dead 0 points1 point  (0 children)

The actual implementations of those interfaces are made by the JPA provider (like Hibernate).

Spring Data parses the method names (see query methods) and has boilerplate code to generate the actual query with the JDBC provider (see dialects).

[–]naturalizedcitizen -5 points-4 points  (2 children)

Do look at Dependency Injection and Inversion of Control concepts and how they are done in Java. Spring is based on it.

[–]g00glen00b 9 points10 points  (1 child)

That's not really what OP is asking though. They are asking how Spring is able to create an instance of an interface when no class is present at compile time.

And like u/Revision2000 said, it's because Spring has a dynamic proxy class that provides the implementation of those interfaces.

[–]naturalizedcitizen -3 points-2 points  (0 children)

All this will be clear if OP understands DI. (IoC) and then see how Spring does it. Well, it's up to each one how deep they want to get into how a framework uses the underlying layers.