I'm using the latest Springframework, and having issues trying to GET an int from my server. All code was writen in Java.
When I interact with the server throught browser everything is OK. And when interacting with the server through the client I'm getting a NullPointerException.
Keep in mind I am a beginner software student.
Server Code (I tried both, works fine when using browser):
public class RestController {
private GameSession gameSession = new GameSession();
#RequestMapping(value = "registerPlayer")
public int registerPlayer(#RequestParam("name") String name, #RequestParam("mode") boolean mode) {
return gameSession.registerPlayer(name, mode);
}
#RequestMapping(value = "registerPlayer/{name}/{mode}")
public int registerPlayer(#PathVariable String name, #PathVariable boolean mode) {
return gameSession.registerPlayer(name, mode);
}
}
Client Code (again tried both, with the same result):
#Component
public class GameSessionClient implements ISeaBattleGame{
#Autowired
private RestOperations restOperations;
private String url;
#Override
public int registerPlayer(String name, boolean singlePlayerMode) {
url = "http://localhost:8080/" + "registerPlayer?name=" + name + "&mode=" + (singlePlayerMode ? 1 : 0);
return restOperations.getForObject(url, int.class);
}
#Override
public int registerPlayer(String name, boolean singlePlayerMode) {
url = "http://localhost:8080/" + "registerPlayer/" + name + "/" + (singlePlayerMode ? 1 : 0);
return restOperations.getForObject(url, int.class);
}
}
RestConfig Code:
#Configuration
public class RestConfig {
#Bean
public RestOperations createRestTemplate(final ClientHttpRequestFactory clientHttpRequestFactory){
return new RestTemplate(clientHttpRequestFactory);
}
#Bean
public ClientHttpRequestFactory clientHttpRequestFactory(#Value("${connect.timeout}") final int connectTimeout, #Value("${read.timeout}") final int readTimeout){
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpComponentsClientHttpRequestFactory.setReadTimeout(readTimeout);
httpComponentsClientHttpRequestFactory.setConnectTimeout(connectTimeout);
return httpComponentsClientHttpRequestFactory;
}
}
App Code:
#SpringBootApplication
public class App implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Autowired
private GameSessionClient gameSessionClient;
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) throws Exception {
int playerNr = gameSessionClient.registerPlayer("test", true);
logger.info("Response: {}", playerNr);
}
}
The return restOperations.getForObject(url, int.class); results in a java.lang.NullPointerException
url: http://localhost:8080/registerPlayer/test/1 or http://localhost:8080/registerPlayer?name=test&mode=1 both result in 1 when using my browser
Any help would be much appreciated, as I'm getting pretty confused from this.
Update you code to below..will remove the NullPointer Exception your getting:
#Bean
public RestOperations restOperations(final ClientHttpRequestFactory clientHttpRequestFactory){
return new RestTemplate(clientHttpRequestFactory);
}
and do this , instead of "Application.class":
public static void main(String[] args){
SpringApplication.run(App.class, args);
}
Related
I'm New in Mocking.
I've a service I'm trying to call is let say name A, I need to test someMethod.
#Service
public class A {
private Logger logger = LoggerFactory.getLogger(getClass());
private final CoreXReader coreXReader;
#Autowired
B b;
#Autowired
C c;
#Async
public void someMethod(Config config) throws Exception {
pushConfig(config);
}
private void pushConfig(Config config) throws Exception {
String url = config.getBaseurl() + config.getId();
ABCRestClient restClient = new ABCRestClient(url);
String jobJson = restClient.callRestMethod(HttpMethod.GET, "");
}
}
sample of ABCRestClient
public class ABCRestClient {
private Logger logger = LoggerFactory.getLogger(getClass());
private String url;
public ABCRestClient(String url) {
this.url = url;
}
public String callRestMethod(HttpMethod method, String payload) throws Exception {
someresponse="example response";
return someresponse;
}
}
I'm trying to test by creating mockSpy but it still Calling its 'callRestMethod'
#RunWith(SpringRunner.class)
#SpringBootTest // (webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Test {
#Autowired
private A a;
private Logger logger = LoggerFactory.getLogger(getClass());
#Before
public void prepareMockDataForService() throws Exception {
ABCRestClient apiClient = new ABCRestClient(config.getBaseurl() + config.getId() );
ABCRestClient apiClientSpy=Mockito.spy(apiClient);
doReturn(getCallResponse()).when(apiClientSpy).callRestMethod(HttpMethod.GET, "");
}
#Test
public void TestPushConfig() throws Exception {
a.someMethod(StubDataGenerator.getConfig());
}
private String getCallResponse() {
return "{"msg":"sample response"}";
}
}
i'm not sure what I'm doing wrong here why its calling the actual callRestMethod as i already create a spy .
I tried using this too Mockito.doReturn(getCallResponse()).when(apiClientSpy.callRestMethod(HttpMethod.GET, ""))
Also, is there any difference in these two statement if I use it Mockito.doReturn() or directly doReturn()? In my case both seems behaving same.
Before I tried with this as well when().thenReturn(); but I read somewhere that use when().thenReturn() when you actually want to make call. Please correct if my understanding is wrong.
You can try mock instead of spy:
#RunWith(SpringRunner.class)
#SpringBootTest // (webEnvironment=
SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Test {
#Autowired
private A a;
private Logger logger = LoggerFactory.getLogger(getClass());
#Before
public void prepareMockDataForService() throws Exception {
ABCRestClient apiClientSpy=Mockito.mock(ABCRestClient.class);
doReturn(getCallResponse()).when(apiClientSpy).callRestMethod(HttpMethod.GET, "");
}
#Test
public void TestPushConfig() throws Exception {
a.someMethod(StubDataGenerator.getConfig());
}
private String getCallResponse() {
return "{"msg":"sample response"}";
}
}
Here is what I'm trying to do:
#SpringBootApplication public class App {
public static final String NAME;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
#Autowired public App(ApplicationArguments arguments) {
NAME = arguments.getSourceArgs()[0]; // ERROR (1)
}
#GetMapping("/" + NAME) public void test() { // ERROR (2)
return NAME;
}
}
The code doesn't work as written because (1) NAME cannot be assigned, and (2) annotation value for #GetMapping must be a constant expression.
I just want #GetMapping to use a value based on a command line argument. How can this be done?
in the first request. spring mvc will init the resource. so your put your dynamic url in haddlermapping.
we need three classes. MyController MyDispatcherServlet DispatcherServletCustomConfiguration
MyController.java
#Component(value="MyController")
public class MyController {
#Autowired
ClaimService claimService;
public ResponseEntity<HttpStatus> insertClaim() {
return new ResponseEntity<>(HttpStatus.OK);
}
}
MyDispatcherServlet.java. after initStrategies.put, your dynamic url into handdlerMapping.
public class MyDispatcherServlet extends DispatcherServlet {
private String url;
public MyDispatcherServlet(String url) {
super();
this.url = url;
}
#Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
List<HandlerMapping> handlerMappings = getHandlerMappings();
for (HandlerMapping handlerMapping : handlerMappings) {
if (handlerMapping instanceof RequestMappingHandlerMapping) {
RequestMappingHandlerMapping requestMappingHandlerMapping = ((RequestMappingHandlerMapping) handlerMapping);
RequestMappingInfo.Builder n = RequestMappingInfo
.paths(url)
.methods(RequestMethod.GET);
try {
Method method = MyController.class.getDeclaredMethod("insertClaim");
requestMappingHandlerMapping.registerMapping(n.build(), "MyController", method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
}
}
DispatcherServletCustomConfiguration.java
#Configuration
public class DispatcherServletCustomConfiguration {
#Value("${myUrl}")
private String url;
#Bean
public DispatcherServlet dispatcherServlet() {
return new MyDispatcherServlet(url);
}
}
run with the command java -jar stackoverflow-1.0-SNAPSHOT.jar --myUrl=abcd
I am coding Dropwizard micro-services that fetch data in a MongoDB database. The micro-services work fine but I'm struggling to use in my DAO the configuration coming from my Dropwizard configuration Java class. Currently I have
public class XDAO implements IXDAO {
protected DB db;
protected DBCollection collection;
/* singleton */
private static XDAO instance;
/* Get singleton */
public static synchronized XDAO getSingleton(){
if (instance == null){
instance = new XDAO();
}
return instance;
}
/* constructor */
public XDAO(){
initDatabase();
initDatabaseIndexes();
}
private void initDatabase(){
MongoClient client = null;
try {
client = new Mongo("10.126.80.192",27017);
db = client.getDB("terre");
//then some other code
}
catch (final MongoException e){
...
}
catch (UnknownHostException e){
...
}
}
}
I want to unhard-code the three arguments in these two lines :
client = new Mongo("10.126.80.192", 27017);
db = client.getDB("terre");
My MongoConfiguration Java class is :
public class MongoConfiguration extends Configuration {
#JsonProperty
#NotEmpty
public String host;
#JsonProperty
public int port = 27017;
#JsonProperty
#NotEmpty
public String db_name;
public String getMongohost() {
return host;
}
public void setMongohost(String host) {
this.host = host;
}
public int getMongoport() {
return port;
}
public void setMongoport(int port) {
this.port = port;
}
public String getDb_name() {
return db_name;
}
public void setDb_name(String db_name) {
this.db_name = db_name;
}
}
My Resource class that uses the DAO is :
#Path("/mongo")
#Produces(MediaType.APPLICATION_JSON)
public class MyResource {
private XDAO xDAO = XDAO.getSingleton();
private String mongohost;
private String db_name;
private int mongoport;
public MyResource(String db_name, String mongohost, int mongoport) {
this.db_name = db_name;
this.mongohost = mongohost;
this.mongoport = mongoport;
}
public MyResource() {
}
#GET
#Path("/findByUUID")
#Produces(value = MediaType.APPLICATION_JSON)
#Timed
public Entity findByUUID(#QueryParam("uuid") String uuid) {
return xDAO.findByUUid(uuid);
}
}
And in my application class there is
#Override
public void run(final MongoConfiguration configuration, final Environment environment) {
final MyResource resource = new MyResource(configuration.getDb_name(), configuration.getMongohost(), configuration.getMongoport());
environment.jersey().register(resource);
}
To solve my problem I tried many things. The last thing I tried was to add these four fields in my XDAO
private String mongohost;
private String db_name;
private int mongoport;
private static final MongoConfiguration configuration = new MongoConfiguration();
Coming with this piece of code in the constructor of the XDAO:
public XDAO(){
instance.mongohost = configuration.getMongohost();
instance.mongoport = configuration.getMongoport();
instance.db_name = configuration.getDb_name();
/* then like before */
initDatabase();
initDatabaseIndexes();
}
When I try this I have a null pointer exception when my initDatabase method is invoked : mongoHost and db_name are null
The problem is that you are creating a new configuration in your XDAO with private static final MongoConfiguration configuration = new MongoConfiguration(); instead of using the config from Dropwizard's run method.
When you do this, the fields host and db_name in the new configuration are null, which is why you are getting the NPE when instantiating XDAO
You need to pass the instance of MongoConfiguration that you get from Dropwizard in your application class to your XDAO, ideally when the singleton XDAO is created so it has non-null values for db_name and host
This code below part of the problem - you are creating the singleton without giving XDAO the MongoConfiguration configuration instance.
public class XDAO implements IXDAO {
//... snip
/* Get singleton */
public static synchronized XDAO getSingleton(){
if (instance == null){
instance = new XDAO(); // no configuration information is included!
}
return instance;
}
/* constructor */
public XDAO(){
initDatabase(); // this call needs db_name & host but you haven't set those yet!!
initDatabaseIndexes();
}
I recommend you modify your application class to create XDAO along the lines of this:
#Override
public void run(final MongoConfiguration configuration, final Environment environment) {
XDAO XDAOsingleton = new XDAO(configuration);
XDAO.setSingletonInstance(XDAOsingleton); // You need to create this static method.
final MyResource resource = new MyResource(configuration.getDb_name(), configuration.getMongohost(), configuration.getMongoport()); // MyResource depends on XDAO so must be created after XAO's singleton is set
environment.jersey().register(resource);
}
You may also need to take initDatabase() etc out of XDAO's constructor depending on if you keep public static synchronized XDAO getSingleton()
I also recommend you change the constructor of MyResource to public MyResource(XDAO xdao). The resource class doesn't appear to need the configuration information, and it is better to make the dependency on an XDAO explicit (you then also don't need to keep the XDAO singleton in a static field inside XDAO's class).
To get MongoDB integrated in a simple way to Dropwizard, please try and use MongoDB Managed Object. I will explain this in 3 simple steps:
Step 1: Create a simple MongoManged class:
import com.mongodb.Mongo;
import io.dropwizard.lifecycle.Managed;
public class MongoManaged implements Managed {
private Mongo mongo;
public MongoManaged(Mongo mongo) {
this.mongo = mongo;
}
#Override
public void start() throws Exception {
}
#Override
public void stop() throws Exception {
mongo.close();
}
}
Step 2: Mention MongoDB Host, Port, DB Name in a config yml file:
mongoHost : localhost
mongoPort : 27017
mongoDB : softwaredevelopercentral
Step 3: Bind everything together in the Application Class:
public class DropwizardMongoDBApplication extends Application<DropwizardMongoDBConfiguration> {
private static final Logger logger = LoggerFactory.getLogger(DropwizardMongoDBApplication.class);
public static void main(String[] args) throws Exception {
new DropwizardMongoDBApplication().run("server", args[0]);
}
#Override
public void initialize(Bootstrap<DropwizardMongoDBConfiguration> b) {
}
#Override
public void run(DropwizardMongoDBConfiguration config, Environment env)
throws Exception {
MongoClient mongoClient = new MongoClient(config.getMongoHost(), config.getMongoPort());
MongoManaged mongoManaged = new MongoManaged(mongoClient);
env.lifecycle().manage(mongoManaged);
MongoDatabase db = mongoClient.getDatabase(config.getMongoDB());
MongoCollection<Document> collection = db.getCollection(config.getCollectionName());
logger.info("Registering RESTful API resources");
env.jersey().register(new PingResource());
env.jersey().register(new EmployeeResource(collection, new MongoService()));
env.healthChecks().register("DropwizardMongoDBHealthCheck",
new DropwizardMongoDBHealthCheckResource(mongoClient));
}
}
I have used these steps and written a blog post and a sample working application code is available on GitHub. Please check: http://softwaredevelopercentral.blogspot.com/2017/09/dropwizard-mongodb-tutorial.html
I am newbie in Spring.
I use AbstractRoutingDataSource to change db connection in runtime and SpringBoot
My code is similar to this https://spring.io/blog/2007/01/23/dynamic-datasource-routing but beans are configured programatically.
public class DatabaseContext {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDatabaseType(String string) {
contextHolder.set(string);
}
public static String getDatabaseType() {
return (String) contextHolder.get();
}
public static void clearDatabaseType() {
contextHolder.remove();
}
}
Everything works fine when I change context like that (pseudocode):
public class Application {
#Autowired
private MyCrudRepository repository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override run(){
DatabaseContext.changeContext("db1");
repository.findAll(); //data from db1 like expected
DatabaseContext.changeContext("db2");
repository.findAll(); //data from db2 like expected
}
}
but when I change context in servlet class (pseudocode)
#Controller
public class MyWebController{
#RequestMapping(someMapping)
HttpEntity someMethod(){
DatabaseContext.changeContext("db1");
repository.findAll(); //data from db1 like expected
DatabaseContext.changeContext("db2");
repository.findAll(); //data from db1
}
}
Context change just one time and I have no idea what's wrong.
I have a little problem. I think this is typical question. However, I can't find good example. My application is using Jersey. And I want to test controller by client as test. Controller has private field - StudentService. When I debug test I see, that field is null. This leads to error. And I need to inject this field. I tried this:
My Controller
#Path("/student")
#Component
public class StudentResourse {
#Autowired
private StrudentService service; // this field Spring does not set
#Path("/getStudent/{id}")
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Student getStudent(#PathParam("id") long id) {
return service.get(id);
}
}
My JUnit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:config.xml")
#TestExecutionListeners({ DbUnitTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class StudentResourseTest extends JerseyTest {
private static final String PACKAGE_NAME = "com.example.servlet";
private static final String FILE_DATASET = "/data.xml";
#Autowired
private StudentService service; // this field is setted by Spring, but I do not need this field for test
public StudentResourseTest() {
super(new WebAppDescriptor.Builder(PACKAGE_NAME).build());
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new HTTPContainerFactory();
}
#Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("restful.server.resource")
.contextParam("contextConfigLocation",
"classpath:/config.xml").contextPath("/")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class).build();
}
#Test
#DatabaseSetup(FILE_DATASET)
public void test() throws UnsupportedEncodingException {
ClientResponse response = resource().path("student").path("getStudent")
.path("100500").accept(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
} }
I guees, that problem is in test class. Because, when I run my application not in test, I can directly request students and everything working fine. But when I test classes, internal field of Controller does not setted. How to fix this bug? Thanks for your answers.
This is in my config.xml
<context:component-scan base-package="com.example" />
<bean id="StudentResourse" class="com.example.servlet.StudentResourse">
<property name="service" ref="studentService" />
</bean>
<bean id="service" class="com.example.service.StudentServiceImpl" />
One issue may be that you're trying to configure your test application in constructor and in configure() method. Use one or another but not both because in this case your configure() method is not invoked and hence you may not be using SpringServlet and everything that is defined in this method.
Reference: https://github.com/jiunjiunma/spring-jersey-test and http://geek.riffpie.com/unit-testing-restful-jersey-services-glued-together-with-spring/
Idea is to get a hold of the application context inside jersey by using ApplicationContextAware interface. There after we can grab the exact bean already created by spring, in your case, StudentService. Below example shows a mocked version of the dependency, SampleService, used to test the resource layer apis.
Resource class delegating the processing to a service layer
#Component
#Path("/sample")
public class SampleResource {
#Autowired
private SampleService sampleService;
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path ("/{id}")
public Sample getSample(#PathParam("id") int id) {
Sample sample = sampleService.getSample(id);
if (sample == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return sample;
}
}
Service layer encapsulating business logic
#Service
public class SampleService {
private static final Map<Integer, Sample> samples = new HashMap<>();
static {
samples.put(1, new Sample(1, "sample1"));
samples.put(2, new Sample(2, "sample2"));
}
public Sample getSample(int id) {
return samples.get(id);
}
}
Unit test for the above resource
public class SampleResourceTest extends SpringContextAwareJerseyTest {
private SampleService mockSampleService;
// create mock object for our test
#Bean
static public SampleService sampleService() {
return Mockito.mock(SampleService.class);
}
/**
* Create our own resource here so only the test resource is loaded. If
* we use #ComponentScan, the whole package will be scanned and more
* resources may be loaded (which is usually NOT what we want in a test).
*/
#Bean
static public SampleResource sampleResource() {
return new SampleResource();
}
// get the mock objects from the internal servlet context, because
// the app context may get recreated for each test so we have to set
// it before each run
#Before
public void setupMocks() {
mockSampleService = getContext().getBean(SampleService.class);
}
#Test
public void testMock() {
Assert.assertNotNull(mockSampleService);
}
#Test
public void testGetSample() {
// see how the mock object hijack the sample service, now id 3 is valid
Sample sample3 = new Sample(3, "sample3");
Mockito.when(mockSampleService.getSample(3)).thenReturn(sample3);
expect().statusCode(200).get(SERVLET_PATH + "/sample/3");
String jsonStr = get(SERVLET_PATH + "/sample/3").asString();
Assert.assertNotNull(jsonStr);
}
}
SpringContextAwareJerseyTest
#Configuration
public class SpringContextAwareJerseyTest extends JerseyTest {
protected static String SERVLET_PATH = "/api";
final private static ThreadLocal<ApplicationContext> context =
new ThreadLocal<>();
protected String getResourceLocation() {
return "example.rest";
}
protected String getContextConfigLocation() {
return getClass().getName();
}
static private String getContextHolderConfigLocation() {
return SpringContextAwareJerseyTest.class.getName();
}
protected WebAppDescriptor configure() {
String contextConfigLocation = getContextConfigLocation() + " " +
getContextHolderConfigLocation();
Map<String, String> initParams = new HashMap<>();
initParams.put("com.sun.jersey.config.property.packages",
getResourceLocation());
initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true");
return new WebAppDescriptor.Builder(initParams)
.servletClass(SpringServlet.class)
.contextParam(
"contextClass",
"org.springframework.web.context.support.AnnotationConfigWebApplicationContext")
.contextParam("contextConfigLocation", contextConfigLocation)
.servletPath(SERVLET_PATH) // if not specified, it set to root resource
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
protected final ApplicationContext getContext() {
return context.get();
}
#Bean
public static ContextHolder contextHolder() {
return new ContextHolder();
}
private static class ContextHolder implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context.set(applicationContext);
}
}
}
Using the above with jersey 1.8