I have a class:
#Component
#NoArgsConstructor
public class ServiceFactory {
private CustomerService customerService;
private ClientService clientService;
private Map<OrderType, SettlementService> settlementServiceMap;
public ServiceFactory(CustomerService customerService, ClientService clientService) {
this.customerService = customerService;
this.clientService = clientService;
this.settlementServiceMap = new EnumMap<OrderType, SettlementService>(OrderType.class){{
put(CUSTOMER_CREDIT_ORDER, customerService);
put(CLIENT_CREDIT_ORDER, clientService);
put(CLIENT_DEBIT_ORDER, clientService);
}};
}
public SettlementService provideService(OrderType orderType){
Optional<SettlementService> settlementService = Optional.ofNullable(settlementServiceMap.get(orderType));
if (!settlementService.isPresent()){
throw new ApplicationException("Wrong order type");
}
return settlementService.get();
}
}
I'm getting NullPointerException since the services have not been initialized. A map contains orderType as a key and reference to service as a value. What is the proper way of populating the map along with services?
Related
I have two classes which are annotated as #Component
#Component
public class ClientMapper {
public Client convert(ClientEntity clientEntity) {
Client client = new Client();
BeanUtils.copyProperties(clientEntity, client);
return client;
}
public ClientEntity convert(Client client) {
ClientEntity clientEntity = new ClientEntity();
BeanUtils.copyProperties(client, clientEntity);
return clientEntity;
}
}
#Component
public class OrderMapper {
public Order convert(OrderEntity orderEntity) {
Order order = new Order();
BeanUtils.copyProperties(orderEntity, order);
return order;
}
public OrderEntity convert(Order order) {
OrderEntity orderEntity = new OrderEntity();
BeanUtils.copyProperties(order, orderEntity);
return orderEntity;
}
}
I injected them into different services
#Service
#AllArgsConstructor
public class ClientServiceImpl implements ClientService {
private final ClientMapper clientMapper;
private final ClientRepository clientRepository;
#Service
#AllArgsConstructor
public class OrderServiceImpl implements OrderService {
private final OrderMapper orderMapper;
private final OrderRepository orderRepository;
private final OrderNumberRepository orderNumberRepository;
But all time my mappers is null. I don't create new Object of them using new command. Also with my repository interfaces everything is fine, so my way to inject my comments(#AllArgsContrustor) works correct.
Little note, I have tests classes where I used #InjectMocks on my services classes. Can it be that my error occupied because of this annotation?
#ExtendWith(MockitoExtension.class)
public class OrderServiceTest {
#Mock
private OrderRepository orderRepository;
#InjectMocks
private OrderServiceImpl orderService;
You are using MockitoExtension, spring won't create component of OrderMapper.
If you need actual implementation. Use #Spy annotation of MockitoExtension.
#ExtendWith(MockitoExtension.class)
public class OrderServiceTest {
#Mock
private OrderRepository orderRepository;
#Spy
private OrderMapper orderMapper = new OrderMapper(); // Note: new OrderMapper() is optional as you have No Argument Constructor
#InjectMocks
private OrderServiceImpl orderService;
Or as a practice #Mock is always best way to go instead of #Spy incase of Unit test.
in my project, I have a login manager class - that calls to "tokenManager" class.
the tokenManager class included a map of tokens, and save there the generated tokens.
I get this error message:
APPLICATION FAILED TO START
***************************
Description:
Field tokens in com.chana.login.TokenManager required a bean of type 'java.util.Map' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'java.util.Map' in your configuration.
The tokenManager class defines a bean of type "map" (with #Autowired)
so I don't know how to resolve that.
Does anyone have an idea?
tokenManager.class:
#Service
#AllArgsConstructor
public class TokenManager {
#Autowired
private Map<String, TokenInfo> tokens;
public boolean isTokenExists(String token) {
return tokens.get(token) != null;
}
public String generageToken(ClientType type) {
TokenInfo info = TokenInfo.generate(type);
tokens.put(info.getToken(), info);
return info.getToken();
}
public void removeToken(String token) {
tokens.remove(token);
}
private boolean isTokenExpired(Date time) {
return new Date().after(DateUtils.addMinutes(time, 30));
}
public void removeExpired() {
tokens.entrySet().removeIf((entry)->
isTokenExpired(entry.getValue().getCreationDate()));
}
}
The loginManager.class call to tokenManager.class:
#Component
public class LoginManager {
private final ApplicationContext context;
#Autowired
private final AdminService adminService;
#Autowired
private TokenManager tokenManager ;
#Autowired
private ClientService clientService;
#Autowired
public LoginManager(ApplicationContext context, AdminService adminService, TokenManager tokenManager) {
this.context = context;
this.adminService = adminService;
this.tokenManager = tokenManager;
}
//continue...
No need of autowire in the TokenManager
#Service
#AllArgsConstructor
public class TokenManager {
private Map<String, TokenInfo> tokens = new HashMap<>();
...
This should be enough
How to create xml bean for the below java class. I am using old spring version, from where i need to create a xml bean for the following "TestSample" class.
#Service
#EnableConfigurationProperties(SampleProperties.class)
public class TestSample{
#Autowired
public ClientService clientService;
#Autowired
public RestTemplate restTemp;
public Map<String, String> testing(String a, String b, String c) throws Exception {
Map<String, String> map = clientService.find(a, b, c);
System.out.println("**=="+map.get(0));
return map;
}
}
ClientService class.
#Service
#Slf4j
#DependsOn("restTemp")
public class ClientService {
public ClientService(
#Autowired final SampleProperties sampleProperties,
#Autowired(required = false) final ObjectMapper pObjectMapper) throws UnknownHostException {
}
//......
}
In Spring Boot I have a class that I want to instantiate by passing parameters in the the constructor in runtime. I am able to do this but all of the AutoWire properties are null and PostConstruct doesn't get called.
Constructor<KafkaController> constructorsA[] = (Constructor<KafkaController>[]) KafkaController.class.getConstructors();
KafkaController kafkaObject = constructorsA[0].newInstance(new Object[] { "1", "2" });
This is the class in question
#Component
public class KafkaController {
private KafkaConsumer<String, String> consumer;
#Autowired
private Util sentinelUtil;
final String subscriberID;
final String interactionID;
#Autowired
public KafkaController(#Value("") String subscriberID, #Value("") String interactionID) {
this.subscriberID = subscriberID;
this.interactionID = interactionID;
}
#PostConstruct
private void initKafka() {
}
}
Do I have to instantiate the class using a different method?
I have an application , and now I am trying to use Spring to refactor it, and I have problem when creating object using new, but I don't know how to solve it.
Here is the realtionship:
I have a Controller, need a CommandService instance, and the CommandService need a RoomService to create AbstractRoom instances to put into RoomService instance's hashmap.
I have two kinds of AbstractRoom called RoomA, RoomB, and they extend from AbstractRoom, and AbstractRoom needs GameService instance.
I will pass a param from commandService to roomService so that the roomservice can create a right room instance.
The problem now, is that I use roomservice.createRoom to create a room which uses new to do that. So Spring can not inject GameService to my Abstract Room thus I have a null gameService.
But CommandService will get some input from user and to delegate to RoomService to create a room for it, so I don't know which Room Instance will be created until the user input something:
CommandService.java:
private String handleCreateRoom(String userID, int playerCount,
Mode roomMode) {
...
AbstractRoom theNewRoom=roomService.createRoom(userID, playerCount, roomMode);
...
}
Here is how I createRoom from RoomService.java:
public AbstractRoom createRoom(String userID,int playerCount,Mode roomMode){
AbstractRoom room = newRoom(roomMode);// create a room based on the roomMode
room.initRoom(userID, playerCount);// init the room
userToRoom.put(userID, room.getRoomNum());//some context
return room;
}
public AbstractRoom newRoom(AbstractRoom.Mode roomMode) {
Integer randomNumObject;
AbstractRoom newRoom;
.....
if(roomMode.equals(Mode.AUTO_JUDGE)||roomMode.equals(Mode.PLAYER_JUDGE)){//wodi room
newRoom=new RoomA(randomNumObject,roomMode);//RoomA
}
....
else{//RoomB
newRoom=new RoomB(randomNumObject);
}
roomMap.put(randomNumObject, newRoom);//some context
return newRoom;
}
Here is my AbstractRoom.java
public abstract class AbstractRoom {
protected Mode roomMode;
#Autowired
protected GameService gameService;
.....
}
And my configuration is :
#Configuration
#EnableAspectJAutoProxy
public class Application {
#Bean
public CommandService commandService(){
return new CommandService();//singleton
}
#Bean
public RoomService roomService(){
return new RoomService();//singleton
}
#Bean
public GameService gameService(){
return new GameService();//singleton
}
Eventually, I solve this problem with letting AbstractRoom as a bean with scope = prototype, and return the instance from roomservice bean.
#Configuration
#EnableAspectJAutoProxy
public class Application {
#Bean
public CommandService commandService(){
return new CommandService();
}
#Bean
public RoomService roomService(){
return new RoomService();
}
#Bean
public GameService gameService(){
return new GameService();
}
#Bean
#Scope("prototype")
public AbstractRoom room(AbstractRoom.Mode roomMode){
RoomService roomService = roomService();
return roomService.newRoom(roomMode);
}
And in RoomService.java , inject an ApplicationContext, and get Room from the container.
public class RoomService {
#Autowired
private ApplicationContext ctx;
public AbstractRoom createRoom(String userID,int playerCount,Mode roomMode){
AbstractRoom room = (AbstractRoom)ctx.getBean(AbstractRoom.class,roomMode);
}
}