Error injecting constructor in play java mongodb - java

I'm trying to inject my dao object in controller. I've done this:
I've a:
1. MongoDBHelper
2. MerchantDAO
3. MerchantService
4. MerchantController
This is MongoDBHelper class:
import javax.inject.Singleton;
#Singleton
public class MongoDBHelper {
private DB db;
private Datastore datastore;
private Configuration config = Play.application().configuration();
private final String SERVER_URL = config.getString("server_url");
private final String USERNAME = config.getString("database.userName");
private final String PASSWORD = config.getString("database.password");
private final String DATABASE_NAME = config.getString("database.name");
public MongoDBHelper() {
try {
MongoClient mongoClient = new MongoClient();
this.db = mongoClient.getDB(DATABASE_NAME);
this.db.authenticate(USERNAME, PASSWORD.toCharArray());
Morphia morphia = new Morphia();
this.datastore = morphia.createDatastore(mongoClient, DATABASE_NAME);
morphia.mapPackage("models");
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
public DB getDB() {
return this.db;
}
public Datastore getDatastore() {
return this.datastore;
}
}
This is MerchantDAO class
public class MerchantDAO {
#Inject MongoDBHelper mongoDBHelper;
private Datastore datastore = mongoDBHelper.getDatastore();
private DB db = mongoDBHelper.getDB();
private static final String AUTH_TOKEN = "authToken";
private static final Config config = ConfigFactory.load(Play.application().configuration().getString("property.file.name"));
public void updateMerchantWithAuthToken(Merchant merchant){
Query<Merchant> query = datastore.createQuery(Merchant.class).field(config.getString("string.email")).equal(merchant.getEmail());
UpdateOperations<Merchant> ops = datastore.createUpdateOperations(Merchant.class).set(AUTH_TOKEN, merchant.getAuthToken()).set("lastRequestTime",merchant.getLastRequestTime());
UpdateResults res = datastore.update(query, ops);
}
}
}
This is MerchantService class:
public class MerchantService {
static final Config config = ConfigFactory.load(Play.application().configuration().getString("property.file.name"));
#Inject
MerchantDAO merchantDAO;
// Creating unique authToken for already logged in merchant
public String createToken(Merchant merchant) {
merchantDAO.updateMerchantWithAuthToken(merchant);
return authToken;
}
}
This is MerchantController
import javax.inject.Inject;
public class MerchantController extends Controller {
#Inject MerchantService merchantService;
public final static String AUTH_TOKEN_HEADER = "X-AUTH-TOKEN";
public static final String AUTH_TOKEN = "authToken";
public static final Config config = ConfigFactory.load(Play.application().configuration().getString("property.file.name"));
public static Merchant getMerchant() {
return (Merchant)Http.Context.current().args.get("merchant");
}
public Result login() throws Exception {
// code to perform login
return ok(); // status success / failure
}
}
I'm getting following error:
ProvisionException: Unable to provision, see the following errors:
1) Error injecting constructor, java.lang.NullPointerException
at daos.MerchantDAO.<init>(MerchantDAO.java:22)
while locating daos.MerchantDAO
for field at services.MerchantService.merchantDAO(MerchantService.java:26)
while locating services.MerchantService
for field at controllers.MerchantController.merchantService(MerchantController.java:21)
while locating controllers.MerchantController
for parameter 2 at router.Routes.<init>(Routes.scala:36)
while locating router.Routes
while locating play.api.inject.RoutesProvider
while locating play.api.routing.Router
1 error
What am I possibly doing wrong? Why is DI not working properly?
Thanks in advance.

I think the problem is with these lines:
private Datastore datastore = mongoDBHelper.getDatastore();
private DB db = mongoDBHelper.getDB();
These are evaluated during the object instance's construction. I believe that injection won't occur until AFTER the object instance has completed construction. Therefore, mongoDBHelper is null while the above assignments are made.
One way to solve this would be to set datastore and db in the method updateMerchantWithAuthToken.

The problem is that you are trying to access the Configuration object during the MongoDBHelper instantiation. You should just inject the play Configuration object to your module's constructor and initialize all properties within the constructor:
#Inject
public MongoDBHelper(Configuration configuration) {
config = Play.application().configuration();
<read the rest of the config values here>
See the note in the configurable bindings section of the D.I. documentation here

Related

#CrossOrigin only works when register one domain

I wanted to make an connection between frontend and backend so I used #CrossOrigin annotation Like below.
#CrossOrigin(origins = "http://localhost:3000, http://server ip:3000, http://backend.com:3000")
#RestController
#RequestMapping("/member")
public class MemberController {
Logger logger = LoggerFactory.getLogger(MemberController.class);
private MemberService ms;
private Encryption encrypt;
private S3FileUploadService sfu;
#Autowired
public MemberController(MemberService ms, Encryption encrypt,S3FileUploadService sfu) {
this.ms = ms;
this.encrypt = encrypt;
this.sfu = sfu;
}
#GetMapping("/login")
public FrontMember login(#RequestHeader("Authorization") String autho) {
logger.info("Authorization : " + autho);
String memberInform = encrypt.aesDecrypt(autho);
String[] idPwd = memberInform.split("/");
Member loginTry = new Member();
loginTry.setEmail(idPwd[0]);
loginTry.setPwd(encrypt.shaEncryption(idPwd[1]));
Member authorizedUser = ms.login(loginTry);
if(authorizedUser == null){
logger.warn("No member info");
return null;
}else{
logger.info("Member Get : "+authorizedUser.toString());
String hashMemberNum = encrypt.aesEncrypt(Integer.toString(authorizedUser.getMemberNum()));
String mgHash = encrypt.aesEncrypt(Integer.toString(authorizedUser.getMg()));
FrontMember fm = new FrontMember(hashMemberNum, authorizedUser.getNickName(), authorizedUser.getPfUrl(),mgHash);
logger.info("Login User : "+fm.toString());
return fm;
}
}
}
But it doesn't work unless I only put one domain on origin like below.
#CrossOrigin(origins = "http://localhost:3000")
I want to put several domain at crossorigin.
How can I solve this problem?
Check the Official document of CrossOrign,we can found below description:
So the reason is that you have made a wrong invocation,if you need to allow multiple origins,you need to use an array contains of string instead of single string
In order to make your code work,you can try with below:
#CrossOrigin(origins = {"http://localhost:3000", "http://server ip:3000", "http://backend.com:3000"})
#RestController
#RequestMapping("/member")
public class MemberController {
}

How to set default values of model class variables from yaml file?

In a service file I would simply use #Value and initialize the variable instially there. I have tried this approach in a model class but (I assume how things get autowired and that its a model class) this results in it always being null.
The need for this comes out that in different environments the default value is always different.
#Value("${type}")
private String type;
I would avoid trying to use Spring logic inside the models as they are not Spring beans themselves. Maybe use some form of a creational (pattern) bean in which the models are constructed, for example:
#Component
public class ModelFactory {
#Value("${some.value}")
private String someValue;
public SomeModel createNewInstance(Class<SomeModel> clazz) {
return new SomeModel(someValue);
}
}
public class SomeModel {
private String someValue;
public SomeModel(String someValue) {
this.someValue = someValue;
}
public String getSomeValue() {
return someValue;
}
}
#ExtendWith({SpringExtension.class})
#TestPropertySource(properties = "some.value=" + ModelFactoryTest.TEST_VALUE)
#Import(ModelFactory.class)
class ModelFactoryTest {
protected static final String TEST_VALUE = "testValue";
#Autowired
private ModelFactory modelFactory;
#Test
public void test() {
SomeModel someModel = modelFactory.createNewInstance(SomeModel.class);
Assertions.assertEquals(TEST_VALUE, someModel.getSomeValue());
}
}

DAML Stream all the active contracts using Java Binding - LedgerView

I am new to DAML, I wanted to query all the active contracts using Java binding, Bot API and keep them into DB (or in-memory) for future query.
As per the docs, LedgerView can keep track of active contracts in-memory. However I am not able to successfully stream the active contracts.
You can find my code here, https://github.com/agrawald/daml-java-bot.
The above code have a schedule task which I am not very proud of.
The code for the class where I create DamlLedgerClient and start a schedule job to trigger the Bot. Please note
#Slf4j
#Service
#RequiredArgsConstructor
public class DamlContractSvc implements InitializingBean {
#Value("${daml.host}")
private String host;
#Value("${daml.port}")
private int port;
#Value("${daml.appId}")
private String appId;
#Value("${daml.party}")
private String party;
#Value("${daml.packageId}")
private String packageId;
#Autowired(required = true)
private ContractCache contractCache;
private DamlLedgerClient client;
#Scheduled(fixedDelay = 5000)
public void fetch() {
final TransactionFilter transactionFilter = new FiltersByParty(
Collections.singletonMap(party, NoFilter.instance));
Bot.wire(appId, client, transactionFilter, (ledgerView) -> Flowable.empty(),
contractCache);
}
#Override
public void afterPropertiesSet() throws Exception {
client = DamlLedgerClient.forHostWithLedgerIdDiscovery(host, port, Optional.empty());
client.connect();
}
}
I believe I should be running some Command at (ledgerView) -> Flowable.empty().
contractCache is a class which takes CreatedContract object and load it in the cache.
I may be doing something entirely wrong. please correct me.
I ditched the Bot approach and started using TransactionClient referring to the way Bot.wire method is implemented. Following is what my implementation looks like
#Slf4j
#Service
#RequiredArgsConstructor
public class DamlContractSvc implements InitializingBean {
#Value("${daml.host}")
private String host;
#Value("${daml.port}")
private int port;
#Value("${daml.appId}")
private String appId;
#Value("${daml.party}")
private String party;
#Value("${daml.packageId}")
private String packageId;
#Autowired(required = true)
private ContractRepo contractRepo;
private DamlLedgerClient client;
private final static AtomicReference<LedgerOffset> OFFSET = new AtomicReference<>(
LedgerOffset.LedgerBegin.getInstance());
#Scheduled(fixedDelay = 5000)
public void fetch() {
final TransactionFilter transactionFilter = new FiltersByParty(
Collections.singletonMap(party, NoFilter.instance));
client.getTransactionsClient().getTransactions(OFFSET.get(), transactionFilter, true).flatMapIterable(t -> {
OFFSET.set(new LedgerOffset.Absolute(t.getOffset()));
return t.getEvents();
}).forEach(contractRepo);
}
#Override
public void afterPropertiesSet() throws Exception {
client = DamlLedgerClient.forHostWithLedgerIdDiscovery(host, port, Optional.empty());
client.connect();
}
}
I am keeping track of OFFSET and fetching everything starting from LedgerOffset.LedgerBegin.
Full codebase is here: https://github.com/agrawald/daml-java-bot.

Spring Boot Configuration Properties not being set

I am trying to set up a clamav virus scanner in a Spring Boot environment. So I want to set the host and port in a properties file, clamav.properties, located in my resources directory along with the application.properties file. it looks like this:
clamav.host=localhost
clamav.port=3310
clamav.timeout=1000
I have this class:
#ConfigurationProperties("clamav.properties")
public class ClamAvClient {
static final Logger logger = LoggerFactory.getLogger(ClamAvClient.class);
#Value("${clamav.host}")
private String clamHost;
#Value("${clamav.port}")
private int clamPort;
#Value("${clamav.timeout}")
private int clamTimeout;
public boolean ping() throws IOException {
logger.debug("Host:"+clamHost+" Port:"+clamPort);
blah.....
}
private static byte[] asBytes(String s) {
return s.getBytes(StandardCharsets.US_ASCII);
}
public String getClamHost() {
return clamHost;
}
public void setClamHost(String clamHost) {
this.clamHost = clamHost;
}
public int getClamPort() {
return clamPort;
}
public void setClamPort(int clamPort) {
this.clamPort = clamPort;
}
public int getClamTimeout() {
return clamTimeout;
}
public void setClamTimeout(int clamTimeout) {
this.clamTimeout = clamTimeout;
}
}
It's not connecting and in the logs I get this:
2017-09-23 20:39:45.947 DEBUG 28857 --- [http-nio-8080-exec-2] xxx.ClamAvClient : Host:null Port:0
So those values are clearly not getting set. What am I doing wrong? I am using the managed version of spring-boot-starter-web, which my Eclipse is saying is 1.4.3-RELEASE
Any Ideas?
Either use #ConfigurationProperties to map group of properties to a Class using Configuration Processor.
Using #Value inside #ConfigurationProperties doesn`t look right.
All you need to map your properties to the class is :
#Configuration
#ConfigurationProperties(prefix="clamav")
public class ClamAvClient {
static final Logger logger = LoggerFactory.getLogger(ClamAvClient.class);
private String host;
private int port;
private int timeout;
//getters and setters
}
prefix ="clamav" matches your prefixes in the properties file.
host,port,timeout matches the properties of the class.

Spring Service class is null

I'm developing a Spring boot application, but I cannot understand why I'm getting an auto wired service null...
I have this class, marked with #Component annotation
#Component
public class Rele {
#SuppressWarnings("unused")
private Pin pin;
private GpioController gpio;
private static GpioPinDigitalOutput relePin;
private static final Logger logger = Logger.getLogger(Rele.class);
private Interruttore interruttore;
#Autowired AccensioneService accensioneService;
public Rele(){
}
// Costruttore
#SuppressWarnings("static-access")
public Rele(Pin pin, Interruttore interruttore) {
this.pin = pin;
this.gpio = GpioFactory.getInstance();
this.relePin = gpio.provisionDigitalOutputPin(pin, "MyRele", PinState.LOW);
this.interruttore = interruttore;
}
public void lightOn() {
if (relePin.isLow()) {
relePin.high();
updateAccensione(interruttore, true);
logger.debug("Rele acceso");
}
}
public void lightOff() {
if (relePin.isHigh()) {
relePin.low();
updateAccensione(interruttore, false);
logger.debug("Rele spento");
}
}
public void updateAccensione(Interruttore interruttore, boolean acceso) {
Date lastDateAccensione = new Date();
try {
logger.debug("AccensioneService is"+accensioneService.toString());
lastDateAccensione = accensioneService.findLastDate(interruttore);
} catch(NullPointerException npe){
logger.debug("Accensione service è: "+accensioneService);
logger.error("ECCOLO:", npe);
lastDateAccensione = new Timestamp(lastDateAccensione.getTime());
}
Accensione accensione = new Accensione();
Date date = new Date();
logger.debug("lastDate:" + lastDateAccensione);
accensione.setDateTime(new Timestamp(date.getTime()));
accensione.setInterruttore(interruttore);
accensione.setIsLit(acceso);
accensione.setLastDateTime(lastDateAccensione);
logger.debug("Accensione è:"+accensione.toString());
accensioneService.saveAccensione(accensione);
}
}
accensioneServiceuses accensioneDaoto perform basic DB operations on the model Accensione.java. Using dao/services goes good in every controller I have.
In this case, Rele.java it's not a #Controller annotated class (because it's not a controller), so I annotated it via #Component to make it scanned by Spring, but I'm getting always a NullPointerException because accensioneService is null.
I use accensioneService also in another controller, and it works normally, I cannot understand why Spring does not recognize it in this class...
Thanks to #Madhusudana Reddy Sunnapu I understood that the problem was in how i created the Rele object. The problem now is how to change the application to achieve the goal.
I have a ReleManager class which contains a map I need to know if a particular Rele has been already instantiated. I autowire Rele in this class to create it.
#Component
public class ReleManager {
#Autowired Rele rele;
private final Logger logger = Logger.getLogger(ReleManager.class);
private Map<Pin, Rele> mappa = new HashMap<Pin, Rele>();
public Rele getRele(Pin pin, Interruttore interruttore){
if(mappa.containsKey(pin) && mappa.get(pin)!=null){
logger.debug("rele già instanziato");
return mappa.get(pin);
} else {
logger.debug("rele da instanziare");
rele.setInterruttore(interruttore);
rele.setPin(pin);
mappa.put(pin, rele);
return rele;
}
}
}
This class is used in a controller method, this is the interesting part. I autowire ReleManager and Rele in this class to use the map above.
rele = releManager.getRele(RaspiPin.getPinByName(relePin), interruttore);
if(lit){
rele.lightOn();
} else {
rele.lightOff();
}
lightOn() method is in Rele.class... now my NullPointerException comes when calling if (relePin.isLow()) { so now relePinis null...

Categories

Resources