How to get Resttemplate Bean in Entity class using autowired - spring

i am trying to write a method in my Entity class before populating the properties of entity class. To Do that i need to call a rest service . I like to bring my resttemplate into my Entity class using Autowired . Is that something possible , If yes how we can do that .
#Entity
#Table(name = "IC_ORDER")
public class ICOrder implements Serializable {
#Id
#GenericGenerator(name = "UUIDGenerator", strategy = "uuid2")
#GeneratedValue(generator = "UUIDGenerator")
#Type(type = "uuid-char")
UUID id;
#Transient
#Autowired
private RestTemplate restTemplate;
#SneakyThrows
int start(Context context,String userId) {
//restTemplate.postForEntity // Trying to call a rest service here . But getting
restTemplate as null , Want to avoid new Resttemplate here.
}
This is the code in Config class
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}

Entities belong to the domain layer. It is better to make them not depends on any external framework or library stuff such as RestTemplate as much as you can. Also, having the domain layer interacts with the external systems directly just does not feel right to me. They should be done in a higher level layer such as service layer. So it is better to have a separate service class like OrderService to do such logic. You can then easily inject the RestTemplate into this service class.
If you insist doing it inside the domain model , please checkout this for how to use #Configurable and AspectJ to do it.

Related

Mockito: How to mock WebClient configuring Beans

I'm using Mockio, Wiremock and WebClient and I want to test my service layer.
My goal is to use an instance of the webclient and do a real request to wiremock.
Therefore I have to use a standard configuration and not my oauth config from the production mode.
In the service class, I execute reuqets to another api. So the class under test ist annotated with #Service.
Here is the class:
#Service
public class UserServiceImpl implements UserService{
private final Logger log = Logger.getLogger(this.getClass().getName());
private final WebClient webClient;
private final ApplicationConstants applicationConstants;
public UserServiceImpl (WebClient webClient, ApplicationConstants applicationConstants) {
this.applicationConstants = applicationConstants;
this.webClient = webClient;
}
#Override
public User getUserById(#NotNull(message = "userId must not be null.") #NotBlank(message = "userId must not be blank.") String userId) {
return webClient.get()...
}
I configured my WebClient to use Oauth via two Bean Methods in a class annotated with #Configuration.
#Configuration
public class WebClientConfig {
#Bean
public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
...
}
/*
Manages the auth process and token refresh process
*/
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
...
}
}
Because I want to use the webClient without oauth to call wiremock, I want to replace the Beans to return a simple Webclient.builder().build();
So I did:
#ExtendWith({SpringExtension.class, WireMockExtension.class, MockitoExtension.class})
public class TestClass {
#Mock
WebClientConfig webClientConfig;
#MockBean
WebClient webClient;
#InjectMocks
UserServiceImpl userService;
In general as I understand Mockito, i would use my class under test ( the userServiceImpl) with #InjectMocks, so a real instance is used and the dependencies are injected. Therefor I have to provide a Mock for the Webclient. As I don't want to Mock the webclient and just want to configure it different, I do not have to use #Mock. Instead it should be somethig like #MockBean as this annotation creates a bean and replaces existing ones in the context. So I have to mock the Webclientconfig class with #Mock and define something like
when(webclientConfig).webclient(any(OAuth2AuthorizedClientManager.class)).thenReturn(Webclient.builder.build);
But this does not work as I always get a nullpointer exception on the call.
So the basic questions are:
Is my understanding of Mockito right?
How do I have to Manage the Webclient config?
Looks like a case of configuring MockBeans before the rest of the application starts up, which is answered here:
Configure #MockBean component before application start
As of this writing, the answer above mentions using #Primary or #MockBean(answer = Answers.CALLS_REAL_METHODS) as workarounds.

Spring constructor injection using java config

I have a Class that accepts the following constructor
public Student(int id, String name, Map<String, List<String>> mapInject) {
super();
this.id = id;
this.name = name;
this.mapInject = mapInject;
}
And from spring Java Config, I am injecting the constructor args like below..
#Configuration
public class JavaConfig {
#Bean
public Employee getEmployeeBean() {
Map<String,List<String>> mapInject = new HashMap<String,List<String>>();
//Add map element
return new Employee(3123,"John",mapInject);
}
}
Am i doing constructor injection here? Is this the right way to do so?
I wouldn't use Spring to handle this bean creation, unless you want ALL employees to have the same id and name which I doubt.
The power behind Spring is its Dependency Injection (DI) where you define beans for providers such as database managers, services, etc. and inject those into your components. Defining a #Bean like you have there serves no purpose as now you can only inject employees with an id of 3123 and name John.
It's important to understand that just because you are using Spring it doesn't mean EVERYTHING needs to be handled as a bean - you will always need standard POJOs for housing and passing around state (such as your Employee class) which doesn't need to have anything to do with Spring.
Down the line you might have an EmployeeService for example which houses business logic to fetch employees from a database or something, this could then be configured as a bean so it can be injected across the application.
EDIT
#Configuration
public class JavaConfig {
#Bean
#Autowired //assuming a sessionfactory been is configured elsewhere
public EmployeeService employeeService(final SessionFactory sessionfactory) {
return new EmployeeService(sessionFactory);
}
}
You could then inject this anywhere (maybe in a controller for example):
#RestController
public class EmployeeController {
private final EmployeeService employeeService;
#Autowired
public EmployeeController(final EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
Where the EmployeeController doesn't need to know or care that the userService has a DB connection and doesn't need to worry about configuring it as Spring will handle all of that.

Auto generate Spring Rest-Controller

currently I have the Task to create a REST api onto an existing service layer in Spring.
This is the Setup:
#Entity
public class Example{
#Id
public Long id;
...
}
public interface ExampleRepository extends CrudRepository<Example, Long> {}
#Service
public class ExampleService{
#Autowired
private ExampleRepository repo;
public List<Example> findAll(){
//do some businesslogic
return repo.findAll();
}
}
#RestController
#RequestMapping("/exampleService/*")
public class ExampleController{
#Autowired
private ExampleService service;
#GetMapping
public List<Example>findAll(){
return service.findAll();
}
}
The controller is only boilerplate to me and I would really like to find a way to generate it automatically because we are talking about a lot of services and even more functions.
I know there is a way to expose the repositories as REST-Endpoints using spring-data-rest but that is not what I want. I want the services to be exposed as REST-Endpoints. Could you please give me a hint on how to do that?
You should write a Generic Rest Controller which then calls your inner services.
You can achieve this by using external resource file for storing the class details and Java Reflection API .

Spring Boot JPA #Transactional #Service does not update, but #Transactional in controller does

I have a very basic Spring Boot/JPA stack app, with a controller, service layer, and repository that does not persist updates as I understand it should.
A trivial Entity:
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
protected Customer() {}
public Customer(String name) { this.name = name; }
// standard getters,setters //
}
A trivial Repository:
#Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {}
A simple Service layer:
// If the service is #Transactional and the controller is not, the update does NOT occur
#Transactional
#Service
public class CustomerService {
private static final Logger LOG = getLogger(CustomerService.class);
#Autowired
private CustomerRepository customerRepository;
boolean updateCustomerName(Long id, String name) {
Customer customer = customerRepository.findOne(id);
if (customer == null) { return false; }
// Modifies the entity
customer.setName(name);
// No explicit save()
return true;
}
}
And a REST controller that uses it all:
// If the controller is #Transactional and the service is not, the update occurs
#RestController
#RequestMapping("/mvc")
public class CustomerController {
#Autowired
private CustomerService customerService;
#RequestMapping(path = "{id}", method = RequestMethod.PUT)
public ResponseEntity updateCustomerName(#PathVariable Long id, #RequestParam("name") String name) {
customerService.updateCustomerName(id,name);
return ResponseEntity.noContent().build();
}
}
These are wired together with a simple one-liner SpringBootApplication
I have SQL debug logs enabled and see the selects, update, etc.
With the code above: When the service method is invoked by the controller, the modified entity is not persisted. SQL logs show the select of the entity but no update.
There is also no update if nothing is marked #Transactional
However, simply by moving the #Transactional annotation from the service class to the controller class, the SQL update does occur.
If I add an explicit customerRepository.save(customer) to the service method, the update also occurs. But my understanding is that the ORM should automatically save modified persistent entities.
I'm sure the issue has something to do with the EntityManager lifecycle in the web request, but I'm puzzled. Do I need to do additional configuration?
Complete example at https://github.com/monztech/SO-41515160
EDIT: This was solved, see below. Per the Spring spec #Transactional does not work in package-private methods and mistakenly did not make the update service method public.
The update will occur if the method is public and the service class has the #Transactional annotation.
I do have another question, however. Why is the #Transactional annotation necessary? (the update does not occur without it) Shouldn't the entity manager still persist the object because of the open session in view mechanism that Spring uses, independent of any transaction?
Make your updateCustomerName method public.

Add role to a method

I use Spring Boot with Spring Security.
To create an new user, the "creating" user should be an admin.
But if the "creating" user only has the standard role...
#PreAuthorize("hasRole('admin')")
#RequestMapping(value = "/users", method = RequestMethod.POST)
public Long createUser(#RequestBody #Valid final UserAppDto user) {
return userService.save(user);
}
...the result is that a non-admin user is able to create a new user.
In my UserApp class, for the role, I have:
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private Set<Role> roles = new HashSet<>();
My main application
#EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class})
#SpringBootApplication
#EnableCaching
#EnableScheduling
public class Application implements SchedulingConfigurer{
#Bean
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
return new ApplicationSecurity();
}
}
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
}
Do not use pre-post annotations on controlers. They use AOP under the hood, so they do not work on controlers unless they implement interfaces or unless you use proxy-target-class=true, which may have other drawbacks (*).
This annotations should be used on services, because service beans are generaly bound in controlers as interfaces and so the AOP machinery will work as expected.
The spring-security way for limiting access to url is via http security, not via method security.
(*) in particular, never mix class proxying and JDK proxying in same application...

Resources