What is the framework class in Spring that distinguishes functionality of #Controller, #Service, #Repository - spring-annotations

I want to understand which class in Spring framework distinguishes functionality of #Controller, #Service, #Repository annotations. Upon comparing source code of these three annotations understood that only class name is different.
Say, how does spring understand StudentController is only Controller and not Service or Repository?
#Controller
public class StudentController {
}
#Service
public class StudentService {
}
#Repository
public class StudentRepository {
}
Source codes of spring stereotype annotations
Controller.class
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Controller {
#AliasFor(
annotation = Component.class
)
String value() default "";
}
Service.class
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Service {
#AliasFor(
annotation = Component.class
)
String value() default "";
}
Repository.class
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Repository {
#AliasFor(
annotation = Component.class
)
String value() default "";
}
Since source code is same for these annotations, their functionality is distinguished (as each one has different use cases) in framework classes somewhere otherwise framework allows users to use these annotations interchangeable.

I want to understand which class in Spring framework distinguishes
functionality of #Controller, #Service, #Repository annotations. Upon
comparing source code of these three annotations understood that only
class name is different.
The usage is nuanced and often your answers are going to be found by searching for references (e.g. in Eclipse.
For example, #Controller is referenced specifically in RequestMappingHandlerMapping.
Say, how does spring understand StudentController is only Controller
and not Service or Repository?
The plumbing knows what to do with specific annotations. To answer your question directly: it knows StudentController is an #Controller because you have annotated it thus. It is not annotated as #Repository, so it's not a repository.
#Controller itself has a RetentionType.RUNTIME so that Spring can inspect / check for it using reflection.
Finally, note that #Controller (and the other stereotypes you mentioned) are themselves #Components. So a type marked as #Controller is implicitly also a #Component.

Related

How to use Rest Service while using Spring Boot & Spring Data Jpa

Im working on a spring boot application for rest service with using spring data jpa. I followed instructors and read much answers but I couldn't fix my rest service.
Here is application.class
package tr.kasim.Application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#EnableJpaRepositories("tr.kasim.Dao")
#EntityScan("tr.kasim.Model")
#ComponentScan({"tr.kasim.Service", "tr.kasim.Application" })
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here is `restcontroller.class
package tr.kasim.Controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import tr.kasim.Service.PersonelService;
import tr.kasim.Model.Personel;
#RestController
public class STRestController {
#Autowired
public PersonelService personelService;
#RequestMapping(value = "/api/personels", method = RequestMethod.GET)
public ResponseEntity<List<Personel>> getPersonels(){
List<Personel> personels = personelService.findAll();
return ResponseEntity.ok().body(personels);
}
}
`
Here is Service.class`
package tr.kasim.Service;
import java.util.List;
import tr.kasim.Model.Personel;
public interface PersonelService {
List<Personel> findAll();
}
`
Here is ServiceImplemantion.class
package tr.kasim.Service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tr.kasim.Dao.PersonelDao;
import tr.kasim.Model.Personel;
#Service
public class PersonelServiceImpl implements PersonelService {
#Autowired
private PersonelDao personelDao;
#Override
#Transactional
public List<Personel> findAll() {
return personelDao.findAll();
}
}
Here is Dao.class
package tr.kasim.Dao;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import tr.kasim.Model.Personel;
#Repository
public interface PersonelDao extends JpaRepository<Personel, Long> {
List<Personel> findAll();
}
Lastly here is my application.properties
#MySql Connection
spring.datasource.url=jdbc:mysql://localhost:3306/exampleproject?verifyServerCertificate=false&useSSL=true
spring.datasource.username=root
spring.datasource.password=*******
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#Jpa/Hibernate
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
#Logging
logging.file=staffTracking.log
logging.level.org.springframework.web=debug
Im not sure about componentScan. When I read answers I discovered someone mentioned about it but I tried and I got still nothing. Please show me where I failed. Best Regards.
I updated Application.class, now I can deploying project but rest service not working still.
How did you try ComponentScan? The issue here seems that you have a package structure like this:
tr.kasim.Application
- Application.java
tr.kasim.Service
- PersonelService.java
- PersonelServiceImpl.java
tr.kasim.Dao
- PersonelDao.java
Now since, the mainClass is in tr.kasim.Application it would scan for bean definitions inside that package (or a sub-package in tr.kasim.Application). So,
either you move the mainClass out to a parent-package like tr.kasim, or
use #ComponentScan({ "tr.kasim.Dao", "tr.kasim.Service", "tr.kasim.Application" }) and so on.
-- Update --
Based on the discussion so far, I'd suggest taking the first option as that reduces the effort to manually enable scan for entity, repository, etc.

Not finding repository class in spring integration test

The methods : findAll(),save(O o), findOne(long id) of interface
Repository is not found in my spring jpa integration test.
package source;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import category.IntegrationTest;
import domain.BankAccount;
import presentation.MessageContext;
import repository.BankAccountRepository;
#RunWith(SpringRunner.class)
#Category(IntegrationTest.class)
#DataJpaTest
public class BankAccountTest {
#Autowired
private BankAccountRepository repository;
#Test
public void should_find_no_customers_if_repository_is_empty() {
Iterable<BankAccount> accounts = repository.findAll();
assertNull(accounts);
}
#Test
public void shuldCreateBankAccount() {
BankAccount accounts = new BankAccount(100);
repository.save(accounts);
BankAccount accountr = repository.findOne(1l);
assertNotNull(accountr);
}
}
The repository interface looks like this
package repository;
import org.springframework.data.repository.Repository;
import domain.BankAccount;
public interface BankAccountRepository extends Repository<BankAccount, Long> {}
I have also implemeneted a configuration file
package repository;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#EnableJpaRepositories
public class PersistentContext {}
the classes is placed like this
Component structure
What must i to compile the code without errors?
interface Repository is empty interface ,it's common interface for spring data repositories . There is no any method , see Repository API .
If you need method findAll(),save(O o), findOne(long id) you need use CrudRepository - it's sub interface for interface Repository , or you can use JpaRepository - it's extension of CrudRepository.

Wildfly throws "Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam" error

Im using wildfly 9.0 to deploy my war file. I have java LocalDateTime, Java Money types defined in my REST GET endpoints.
When i deploy my war file, i get following error[1]. Based on this answer [2] I have written "ParamConverterProvider" implementations for both types.
It was working fine( I haven't seen same issue again till now) and now i get same issue.
Any clue?
[1]
Caused by: java.lang.RuntimeException: Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam(\"totalMoneyVolumeForPeriod\") on public javax.ws.rs.core.Response com.test.rest.StockEndpoint.getItems(java.lang.Integer,java.lang.Integer,java.lang.String,java.lang.String,java.lang.Long,org.javamoney.moneta.Money,java.util.Set,java.lang.String) for basetype: org.javamoney.moneta.Money"}}}}
[2]
jaxrs could not find my custom (de)serializers for joda.money type
Sample code
package com.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import javax.money.Monetary;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;
import org.javamoney.moneta.Money;
#Provider
public class MoneyConverterProvider implements ParamConverterProvider {
private final MoneyConverter converter = new MoneyConverter();
#Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
if (!rawType.equals(Money.class)) return null;
return (ParamConverter<T>) converter;
}
public class MoneyConverter implements ParamConverter<Money> {
public Money fromString(String value) {
if (value == null ||value.isEmpty()) return null; // change this for production
return Money.of(new BigDecimal(value), Monetary.getCurrency("AUD"));
}
public String toString(Money value) {
if (value == null) return "";
return value.toString(); // change this for production
}
}
}
Application claas
package com.test;
import javax.ws.rs.core.Application;
import com.test.autogen*;
import io.swagger.jaxrs.config.BeanConfig;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
#ApplicationPath("/rest")
public class RestApplication extends Application {
public RestApplication() {
BeanConfig beanConfig = new BeanConfig();
//beanConfig.setVersion("1.0");
beanConfig.setSchemes(new String[] { "http" });
beanConfig.setTitle("My API");
beanConfig.setBasePath("/rest");
beanConfig.setResourcePackage("com.test.autogen");
beanConfig.setScan(true);
}
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
set.add(EmailEndpoint.class);
set.add(StockEndpoint.class);
set.add(io.swagger.jaxrs.listing.ApiListingResource.class);
set.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
return set;
}
}
When you are using classpath scanning, JAX-RS components annotated with #Path or #Provider will get picked up and registered. There are a couple way to use classpath scanning. The most common way is to just have an empty Application class annotated with #ApplicationPath
#ApplicationPath("/api")
public class MyApplication extends Application {}
This is enough for a JAX-RS application to be loaded, and to have the application's classpath scanned to components to register.
But, per the specification, once we override any of the Set<Object> getSingletons or Set<Class> getClasses methods of the Application class, and return a non-empty set, this automatically disables classpath scanning, as it is assumed we want to register everything ourselves.
So in previous cases, you were probably just using classpath scanning. In this case, you need to explicitly add the provider to the set of classes in your getClasses method, since you overrode the method to add other component classes.

Can i return a Stream from a spring jpa repository using a querydsl predicate argument

I'm using spring data and have a repository that extends JpaRepository and QueryDslPredicateExecutor. I get a list of entities from the repository by calling the Iterable findAll(Predicate p) method. I was wondering, is it possible to get a Stream returned from the repository passing in a querydsl predicate as an argument?
as described in https://github.com/spring-projects/spring-data-commons/issues/1169#issuecomment-752400977, you can declare your own method that returns List<...>
import java.util.List;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import com.querydsl.core.types.Predicate;
#Repository
public interface MyEntityRepository extends MongoRepository<MyEntity, ObjectId>, QuerydslPredicateExecutor<MyEntity> {
List<MyEntity> findAll(Predicate predicate);
}
then simply
myEntityRepository.findAll(myPredicate).stream()....
I think it isn't possible right now. Check this issue: https://jira.spring.io/browse/DATACMNS-704

Getting a reference to a Jersey REST resource method from the URL

I'm doing some performance testing, and I want to be able to call a resource method without going through the network. I already have a framework for generating URLs, and I'd like to be able to reuse it.
For example, given the URL: www.example.com:8080/resource/method, I want to get a reference to the resource method that it calls, so that I can run it without making a network-level HTTP request. I.e., in the example below, I want to use the URL "www.frimastudio.com:8080/time" to get a reference to the method getServerTime() that I can then call directly.
Does Jersey (or something else?) provide a way to do this, or do I have to import the specific Resource class I want to call, instantiate it, etc.? Thanks in advance!
Yes jersey is RESTful API that allow routes configuration (only with annotations)
Example :
package com.frimastudio.webservice.controller.route;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.joda.time.DateTime;
import com.frimastudio.webservice.controller.representation.Time;
#Path("/time")
#Produces(MediaType.APPLICATION_JSON)
public class TimeResource
{
public TimeResource()
{
}
#GET
public Time getServerDate()
{
return new Time(new DateTime());
}
}
with Time being a Jackson representation :
package com.frimastudio.webservice.controller.representation;
import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.DateTime;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Time
{
#NotEmpty
#JsonProperty
private String date;
public Time()
{
// Jackson deserialization
}
public Time(String date)
{
super();
this.date = date;
}
public Time(DateTime date)
{
super();
this.date = date.toString();
}
}
This doesn't seem to be possible, based on looking at the Jersey code. The lookup is performed by HttpMethodRule.Matcher, which is a private class used only to implement HttpMethodRule.accept.
Seems to me everything in accept up to if (s == MatchStatus.MATCH) { could be pulled into its own method and exposed to the user.