I have found a few questions similar to the one I'm posting but I'm not getting from them what I really need.
I'm still struggling to implement my CustomMembershipProvider using Microsoft Unity DI.
Custom Membership:
public class CustomMembershipProviderService : MembershipProvider
{
private readonly IUserService _userService;
public CustomMembershipProviderService(IUserService userService)
{
this._userService = userService;
}
public override string ApplicationName
{
...
User Service:
public class UserService : IUserService
{
private readonly IUserRepository _repository;
private readonly IUnitOfWork _unitOfWork;
public UserService(IUserRepository repository, IUnitOfWork unitOfWork)
{
this._repository = repository;
this._unitOfWork = unitOfWork;
}
...
AccountController:
public class AccountController : Controller
{
// next line is what I don't feel too sure about what to do?
// shouldn't my controller constructor use an Interface as its property?
private readonly CustomMembershipProviderService _customMembershipProviderService;
public AccountController(CustomMembershipProviderService customMembershipProviderService)
{
this._customMembershipProviderService = customMembershipProviderService;
}
...
How can I create an interface for my MembershipProvider class?
I've tried:
public interface ICustomMembershipProvider : MembershipProvider
but I don't think that works, so I'm stuck, and don't know how to implement the MembershipProvider using my repositories, UoW, services, and Unity DI
Answer to the second question
The issue with the MembershipProvider and RoleProvider is that they are not built by the container, but by the framework. AFAIK the only way to set the active membership provider is the web.config file.
So, if you want to use the container to resolve dependencies like repositories, services etc. via the container, you have to use the good old (I'm kidding) Service Locator pattern.
public class CustomMebershipProvider : ICustomMebershipProvider {
public bool ValidateUser(string user, string pwd) {
var svc = Global.Container.Resolve<IMyService>();
/* ... */
}
}
To the first question
You can still inject the active membership provider in the controllers using Constructor Injection.
First of all, create an interface with all methods you need. The issue here is that MembershipProvider is a concrete class, so you can't inherit an interface from it. Just create your new interface, copying method signatures of function you need from MembershipProvider:
public interface ICustomMembershipProvider {
bool MyMethod();
/* From MembershipProvider */
bool ValidateUser(string username, string password);
/* ... */
}
Then let your provider implement it and inject:
Container
.RegisterType<ICustomMembershipProvider>(
new InjectionFactory(c => (ICustomMembershipProvider) Membership.Provider))
Of course, you still have to register your custom membership provider in the web.config.
Related
I've thought like this I have service classses. And this service classes are in the same package and different services can need other services methods. So I had to use protected methods.
After that I organized my service class like this:
#Service
public class LessonService {
private final LessonRepository lessonRepository;
public LessonService(LessonRepository lessonRepository) {
this.lessonRepository = lessonRepository;
}
protected Lesson saveLesson(Lesson lesson) {
return lessonRepository.save(lesson);
}
protected List<Lesson> showAllLessons(){
return lessonRepository.findAll();
}
}
Then I created a controller class which is belong to controller package.
#RestController
public class LessonController {
private final LessonService lessonService;
public LessonController(LessonService lessonService) {
this.lessonService = lessonService;
}
#PostMapping("/saveLesson")
public Lesson saveLesson(#RequestBody Lesson lesson) {
return lessonService.
}
I had a instance of LessonService class in my LessonController, so I was thinking like I can reach LessonService methods which is like saveLesson(); over the lessonService instance. but I couldn't.
So I guess I shouldn't made these methods protected. Am I wrong?
Yes, if you want to keep your service classes and controller classes separated in different packages you need use the public modifier on the methods you want to expose to the controller's package.
The fact that you have exposed the constructor of the service class only means that you have allowed classes from other packages to create instances of the service class. It does not automatically mean that the controller class can access every metod on the instantiated object.
I use spring boot 2.
I need to validate many condition, instead of creating many if, I create a class for every condition who implements isValid method.
public interface Rulecondition<T>{
boolean isValid(){
}
public class ClientGroup implements Rulecondition<Billing>{
private Billing billing;
public ClientGroup(Billing billing){
this.billing=billing;
}
#Override
public boolean isValid(){
return true; //only for example...
}
}
I create a class who use a stream of all condition and verify if everything is valid
#Component
public class ConditionRuleEngine{
private List<Rulecondition> rules = new ArrayList<>();
public ConditionRuleEngine(){
}
public void addRule(Rulecondition rule){
rules.add(rule);
}
public boolean conditionApply(){
retunr rules.stream().allMatch(r->.isValid()));
}
}
In a service class, I autowired ConditionRuleEngine
#Service
public class OperationService(){
private final ConditionRuleEngine conditionRuleEngine;
#Autowired
public OperationService OperationService(final ConditionRuleEngine conditionRuleEngine){
this.conditionRuleEngine=conditionRuleEngine;
}
public void execute(Billing billing){
//need to add condition
conditionRuleEngine.run();
}
}
Is there any better way to add condition then creating a new?
ClientGroup cg = new ClientGroup(billing);
conditionRuleEngine.add(cg);
Yes, but there is one change that would help your situation: Removing the generic type argument, T, from the Rulecondition interface. Since Rulecondition only contains a isValid method that does not depend on the generic parameter, T, that parameter can be safely removed:
public interface RuleCondition {
boolean isValid();
}
The reason for this removal is that it simplifies the Spring-based solution to your problem. Without that generic parameter, you can now mark each of your RuleCondition implementations with #Component (making them eligible for dependency injection) and autowire a List<RuleCondition> into your ConditionRuleEngine class:
#Component
public class ConditionRuleEngine {
#Autowired
private List<RuleCondition> rules;
// ...other implementation details...
}
Spring will inject all of the components that implement RuleCondition into the rules field.
While removing the generic parameter, T, simplifies the solution, it is not required.
If you do need to maintain the generic parameter, T, then you can autowire the RuleCondition for each generic parameter by specifying the parameter in the List type:
public interface RuleCondition<T> {
boolean isValid(T value);
}
#Component
public class ClientGroup implements RuleCondition<Billing> {
#Override
public boolean isValid(Billing value) {
// ...
}
}
#Component
public class ConditionRuleEngine {
#Autowired
private List<RuleCondition<Billing>> billingRules;
#Autowired
private List<RulecCndition<Other>> otherRules;
// ...other implementation details...
}
Spring will inject all RuleCondition objects that match the generic parameter. For example, billingRules will contain a List of all RuleCondition<Billing> (and will not include any RulecCndition<Other> objects.
We have a web service that one of its parameters is called origin and this origin is always validated against a code in the database.
For each one of our services I have to validate this code. This code does not change so I want to keep it in a constant, but I still have to validate it to prevent clients from sending a wrong code.
Basically what I want is this:
#Service
public class Service {
#Autowired
private LogBS logBS;
// I know this cannot be used in a static context.
public static final Long CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
public void validateOriginCode(final Long origin) {
if (!origin.equals(CODE)) {
throw new ServiceException("Wrong origin code!");
}
}
}
I know something similar can be done with Spring caching, but is it possible to do it with a constant?
I would rather go with this:
#Service
public class CodeValidatorService {
private LogBS logBS;
private Long CODE;
#Autowired
public CodeValidatorService(LogBS logBS){
this.logBS = logBS;
CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
if (CODE == null){
throw new ServiceException("Code cannot be read from DB!");
}
}
public void validateOriginCode(final Long origin) {
if (!origin.equals(CODE)) {
throw new ServiceException("Wrong origin code!");
}
}
}
Just as a code review, I prefer injecting dependencies in the constructor rather than using #Autowired in the field directly, it makes the service testable. You could also try to read the code in a #PostConstruct method, but I think it's better to do it in the constructor so you always have the service in a ready-to-go state.
For using it in the rest of your services, inject the CodeValidatorService instance on them:
#Service
public class OtherService {
private CodeValidatorService codeValidatorService;
#Autowired
public OtherService(CodeValidatorService codeValidatorService){
this.codeValidatorService = codeValidatorService;
}
public void performAction(final Long origin) {
codeValidatorService.validateOriginCode(origin);
//do the rest of your logic here
}
}
See also:
Spring Beans and dependency injection
Setter injection versus constructor injection
You can have a constantsProvider class
#Component
public class ConstantsProvider {
#Autowired
private LogBS logBS;
private String CODE;
#PostConstruct
public void init() {
CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
}
public String getCode() {
return CODE;
}
}
Add this snippet of code to Service class
#Autowired
private ConstantsProvider constantsProvider;
You can use constantsProvider.getCode() in your services. This way CODE is going to be immutable and not defined in a static context.
Note: If you have more constants similar to this, there is a better way to define the ConstantsProvider class. If there is only one, I would stick to the above implementation.
Edit 1:
If you need it in all the service classes, make the constantsProvider a spring bean and initialize the CODE there itself. Updated the answer
package com.lhoussaine.springjsfjpa.entities;
#Table(name="address")
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String streetNumber;
private String streetName;
private String city;
getter/setter
}
and I Have 30 entities.
Now repositories:
package com.lhoussaine.springjsfjpa.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.repository.annotation.RestResource;
import com.lhoussaine.springjsfjpa.entities.Address;
#RestResource(rel="address", path="address")
public interface AddressRepository extends JpaRepository<Address,Integer> {
}
Here I dont need to implemente CRUD operation! thanks to spring-data-jpa! And I want same standard for controller and services:
public interface IAddressService {
}
package com.lhoussaine.springjsfjpa.services.generic;
import java.util.List;
public abstract class GenericService<T,K> {
public abstract T create(T saved);
public abstract void remove(T deleted);
public abstract T findById(K id) ;
public abstract List<T> findAll();
public abstract T removeById(K id);
}
package com.lhoussaine.springjsfjpa.services.impl;
#Service
#Transactional
public class AddressService extends GenericService<Address, Integer> implements IAddressService {
#Autowired private AddressRepository iaddressRepository;
public Address create(Address saved) {
Address address=saved;
return iaddressRepository.save(address);
}
public void remove(Address deleted) {
iaddressRepository.delete(deleted);
}
public Address findById(Integer id) {
return iaddressRepository.findOne(id);
}
public List<Address> findAll() {
return iaddressRepository.findAll();
}
public Address removeById(Integer id) {
Address addr= iaddressRepository.findOne(id);
if(addr!=null){
iaddressRepository.delete(addr);
}
return addr;
}
}
Now the question is: with controller how I do?
Develop a controller for each class? knowing that I have 30 service classes.
Is there something approaching the same standard such as Spring Data JPA but for services and controller?
As you see with services classes! I'm obliged to make GenericService classes and create an interface for each class that I have in my package entities.
The controllers and the services should not be generic. Although it's understandable that every entity in your app could be created or found by ID, the services should only have the methods needed to implement the business logic of the app.
And the controllers should be created to implement the UI layer of your app. So, once you have a specification (or a clear idea in mind) of how a specific page of your application should look like and work, then implement te controller and the services to implement this page.
If your app is so generic that all it does is create, update and delete rows in tables, then you don't need to implement anything: a generic database web interface like PHPMyAdmin will do.
You can use generic service and controllers only without annotations, i.e with XML configuration. For controllers you also have to set Map<[methodName],org.springframework.web.bind.annotation.RequestMapping> for each controller and extend (override) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping to use it.
See example https://sites.google.com/site/beigeerp/home/spring-generic-controller
This is an Spring MVC project with Hibernate.
I'm, trying to make a Logger class that, is responsible for inputting logs into database.
Other classes just call proper methods with some attributes and this class should do all magic.
By nature it should be a class with static methods, but that causes problems with autowiring dao object.
public class StatisticLogger {
#Autowired
static Dao dao;
public static void AddLoginEvent(LogStatisticBean user){
//TODO code it god damn it
}
public static void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){
//TODO code it god damn it
}
public static void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){
ExceptionLogBean elb=new ExceptionLogBean();
elb.setStuntDescription(e);
elb.setSourcePage(page);
elb.setParameters(parameters);
if(dao!=null){ //BUT DAO IS NULL
dao.saveOrUpdateEntity(elb);
}
}
How to make it right? What should I do not to make dao object null?
I know that I could pass it as a method parameter, but that isn't very good.
I'm guessing that autowired can't work on static objects, because they are created to early to autowiring mechanism isn't created yet.
You can't #Autowired a static field. But there is a tricky skill to deal with this:
#Component
public class StatisticLogger {
private static Dao dao;
#Autowired
private Dao dao0;
#PostConstruct
private void initStaticDao () {
dao = this.dao0;
}
}
In one word, #Autowired a instance field, and assign the value to the static filed when your object is constructed. BTW, the StatisticLogger object must be managed by Spring as well.
Classical autowiring probably won't work, because a static class is not a Bean and hence can't be managed by Spring. There are ways around this, for example by using the factory-method aproach in XML, or by loading the beans from a Spring context in a static initializer block, but what I'd suggest is to change your design:
Don't use static methods, use services that you inject where you need them. If you use Spring, you might as well use it correctly. Dependency Injection is an Object Oriented technique, and it only makes sense if you actually embrace OOP.
I know this is an old question but just wanted to share what I did,
the solution by #Weibo Li is ok but the problem it raises Sonar Critical alert about assigning non static variable to a static variable
the way i resolved it with no sonar alerts is the following
I change the StatisticLogger to singlton class (no longer static)
like this
public class StatisticLogger {
private static StatisticLogger instance = null;
private Dao dao;
public static StatisticLogger getInstance() {
if (instance == null) {
instance = new StatisticLogger();
}
return instance;
}
protected StatisticLogger() {
}
public void setDao(Dao dao) {
this.dao = dao;
}
public void AddLoginEvent(LogStatisticBean user){
//TODO code it god damn it
}
public void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){
//TODO code it god damn it
}
public void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){
ExceptionLogBean elb=new ExceptionLogBean();
elb.setStuntDescription(e);
elb.setSourcePage(page);
elb.setParameters(parameters);
if(dao!=null){
dao.saveOrUpdateEntity(elb);
}
}
I created a service(or Component) that autowire the service that i want and set it in the singlton class
This is safe since in spring it will initialize all the managed beans before doing anything else and that mean the PostConstruct method below is always called before anything can access the StatisticLogger
something like this
#Component
public class DaoSetterService {
#Autowired
private Dao dao0;
#PostConstruct
private void setDaoValue () {
StatisticLogger.getInstance().setDao(dao0);
}
}
Instead of using StatisticLogger as static class I just use it as StatisticLogger.getInstance() and i can access all the methods inside it
You can pass the DAO to StatisticLogger from where you call it.
public static void AddLoginEvent(LogStatisticBean user, DAO dao){
dao.callMethod();
}
It might be too late to put an answer to this question, especially when a question is already having an accepted answer. But it might help others in case they face the same issue.
inside the StatisticLogger class create an instance of the Dao service.
public static Dao daoService = new Dao();
then, auto-wire the service instance through the constructor of the StatisticLogger class.
#Autowired
public functionName(Dao daoService0) {
this.daoService = daoService0;
}
//use this service as usual in static class
daoService.fun();
I think this is the simplest solution for the problem.