I've got a simple java web service sample program from the internet:
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import java.util.Date;
#WebService
interface IService {
void hello(#WebParam(name="username") String username);
}
#WebService(targetNamespace = "ServiceImpl", endpointInterface="IService")
class ServiceImp implements IService{
#Override
public void hello(#WebParam(name = "username") String username) {
System.out.println("hello " + username + " now is " + new Date());
}
}
public class ServiceMain {
public static void main(String[] args) {
String address = "http://localhost:7777/myService";
Endpoint.publish(address, new ServiceImp());
System.out.println("OK");
}
}
It compiles and runs with exception:
Exception in thread "main" java.lang.NullPointerException
at com.sun.xml.internal.ws.model.RuntimeModeler.getPortTypeName(RuntimeModeler.java:1618)
at com.sun.xml.internal.ws.model.RuntimeModeler.getPortTypeName(RuntimeModeler.java:1584)
at com.sun.xml.internal.ws.server.EndpointFactory.create(EndpointFactory.java:226)
at com.sun.xml.internal.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:144)
at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:563)
at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:545)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.createEndpoint(EndpointImpl.java:308)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:231)
at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:126)
at javax.xml.ws.Endpoint.publish(Endpoint.java:240)
at ServiceMain.main(ServiceMain.java:22)
So where does this code snippet get wrong, and how to fix it?
Thanks a lot.
You have to provide fully qualified name for endpoint interface. Try this if you wanna lose the endpoint interface.
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import java.util.Date;
interface IService {
void hello(String username);
}
#WebService(targetNamespace = "ServiceImpl")
class ServiceImp implements IService{
public void hello(#WebParam(name = "username") String username) {
System.out.println("hello " + username + " now is " + new Date());
}
}
public class ServiceMain {
public static void main(String[] args) {
String address = "http://localhost:7777/myService";
Endpoint.publish(address, new ServiceImp());
System.out.println("OK");
}
}
Otherwise, assuming your endpoint interface resides in a package called your.pkg, try this.
package your.pkg;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import java.util.Date;
#WebService
interface IService {
void hello(String username);
}
#WebService(targetNamespace = "ServiceImpl", endpointInterface="your.pkg.IService")
class ServiceImp implements IService{
public void hello(#WebParam(name = "username") String username) {
System.out.println("hello " + username + " now is " + new Date());
}
}
public class ServiceMain {
public static void main(String[] args) {
String address = "http://localhost:7777/myService";
Endpoint.publish(address, new ServiceImp());
System.out.println("OK");
}
}
I was able to run it with both approaches and started getting WSDL from endpoint :- http://localhost:7777/myService?wsdl
Related
let's say that in my spring(boot) yaml config file I have a list of commands:
commands: [add,delete,copy,move]
and the corresponding class in my spring(boot) project:
public class Command {
private String name;
public Command(String name) {
this.name = name;
}
public void execute() {
System.out.println(name);
}
public String getName() {
return name;
}
}
How can I dynamically/adaptively generate the right number of command beans, then gather/autowire them in a separate class as below ?
public class Menu {
#Autowired
List<Command> commands;
public void display() {
commands.forEach(cmd -> System.out.println(cmd.getName());
}
}
Thank you very much in advance for your time and your expertise.
Regards
For dynamic bean registration, you can use ImportBeanDefinitionRegistrar.
The code will be like this:
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
#Configuration
#Import(CommandsConfiguration.Registrar.class)
public class CommandsConfiguration {
static class Registrar implements ImportBeanDefinitionRegistrar {
#Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
final List<String> commands = // read commands from environemnt/config
for (String command : commands) {
final String beanName = command + "Command";
final BeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Command.class, () -> new Command(command))
.getBeanDefinition();
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
The following code is my soap web service with CRUD operations:
UserService.java
package com.gpcoder.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
#WebService
#SOAPBinding(style = SOAPBinding.Style.RPC)
public interface UserService {
#WebMethod
int insert(User user);
#WebMethod
boolean update(User user);
#WebMethod
boolean delete(int id);
#WebMethod
User get(int id);
#WebMethod
User[] getAll();
}
UserServiceImpl.java
package com.gpcoder.ws;
import java.util.HashMap;
import java.util.Map;
import javax.jws.WebService;
#WebService(endpointInterface = "com.gpcoder.ws.UserService")
public class UserServiceImpl implements UserService {
private static final Map<Integer, User> USERS = new HashMap<>();
#Override
public int insert(User user) {
Integer id = generateUniqueId();
user.setId(id);
USERS.put(id, user);
return id;
}
private int generateUniqueId() {
return USERS.keySet().stream().max((x1, x2) -> x1 - x2).orElse(0) + 1;
}
#Override
public boolean update(User user) {
return USERS.put(user.getId(), user) != null;
}
#Override
public boolean delete(int id) {
return USERS.remove(id) != null;
}
#Override
public User get(int id) {
return USERS.getOrDefault(id, new User());
}
#Override
public User[] getAll() {
return USERS.values().toArray(new User[0]);
}
}
SoapPublisher.java
package com.gpcoder.ws;
import javax.xml.ws.Endpoint;
public class SoapPublisher {
public static final String WS_URL = "http://localhost:8080/ws/users";
public static void main(String[] args) {
Endpoint.publish(WS_URL, new UserServiceImpl());
System.out.println("Server is published!");
}
}
I would like to use the feign-soap library to call these soap API. I tried to implement it following the feign-soap document. Here is my client-side code:
pom.xml
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-soap -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-soap</artifactId>
<version>10.2.3</version>
</dependency>
UserService.java
import java.util.ArrayList;
import java.util.List;
import com.gpcoder.model.User;
import feign.Headers;
import feign.RequestLine;
#Headers({ "Content-Type: text/xml" })
public interface UserService {
#RequestLine("POST /get")
#Headers({ "SOAPAction: get" })
String getUser(int id);
#RequestLine("POST /insert")
#Headers({ "SOAPAction: insert" })
String createUser(User user);
#RequestLine("POST /update")
#Headers({ "SOAPAction: update" })
String updateUser(User user);
#RequestLine("POST /delete")
#Headers({ "SOAPAction: delete" })
String deleteUser(int id);
default List<String> getUsers(int... ids) {
List<String> orders = new ArrayList<>();
for (int id : ids) {
orders.add(this.getUser(id));
}
return orders;
}
}
FeignClientCreator.java
import feign.Feign;
import feign.jaxb.JAXBContextFactory;
import feign.soap.SOAPDecoder;
import feign.soap.SOAPEncoder;
import feign.soap.SOAPErrorDecoder;
public class FeignClientCreator {
public static final String BASE_URL = "http://localhost:8080/ws/users";
public static <T> T getService(Class<T> clazz) {
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8")
.withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
.build();
return Feign.builder()
.encoder(new SOAPEncoder(jaxbFactory))
.decoder(new SOAPDecoder(jaxbFactory))
.errorDecoder(new SOAPErrorDecoder())
.target(clazz, BASE_URL);
}
}
FeignClientExample.java
import java.io.IOException;
import com.gpcoder.helper.FeignClientCreator;
import com.gpcoder.model.User;
import com.gpcoder.service.UserService;
public class FeignClientExample {
private static UserService userService;
public static void main(String[] args) throws IOException {
userService = FeignClientCreator.getService(UserService.class);
createUser();
}
private static void createUser() throws IOException {
User user1 = new User();
user1.setId(1);
user1.setUsername("gpcoder.com");
System.out.println("createUser1: " + userService.createUser(user1));
}
}
I don't know where is my code wrong. When I run my program, it show error log:
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Cannot find dispatch method for {}user
at feign.soap.SOAPErrorDecoder.decode(SOAPErrorDecoder.java:68)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
at com.sun.proxy.$Proxy3.createUser(Unknown Source)
at com.gpcoder.FeignClientExample.createUser(FeignClientExample.java:32)
at com.gpcoder.FeignClientExample.main(FeignClientExample.java:16)
Does anyone already worked with this library or have some documents about it please give me some information?
I have a class which has the following
package com.example.misc;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.authentication.PreemptiveBasicAuthScheme;
import org.junit.BeforeClass;
public class QueryEndpoint {
#BeforeClass
public static void setup() {
RestAssured.port = 8010;
PreemptiveBasicAuthScheme authScheme = new PreemptiveBasicAuthScheme();
authScheme.setUserName("username123");
authScheme.setPassword("password123");
RestAssured.authentication = authScheme;
String basePath;
basePath = "/api/version1/";
RestAssured.basePath = basePath;
String baseHost;
baseHost = "http://localhost";
RestAssured.baseURI = baseHost;
}
}
Then in another class, I have a test...
package com.example.tests;
import com.example.misc.QueryEndpoint;
import org.junit.Test;
import static com.jayway.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
public class ApiTest extends QueryEndpoint{
#Test
public void verifyTopLevelURL() {
given()
.auth(). preemptive().basic("username", "password")// THIS LINE DON'T WORK, need to add here something?
.contentType("application/json")
.when().get("/123456789").then()
.body("fruit",equalTo("123456789"))
.body("fruit.apple",equalTo(37))
.body("fruit.red",equalTo("apple"))
.statusCode(200);
}
My Question is: How do I use the header + user + pass set in the method setup() and call that to be used in my test verifyTopLevelURL.
You can directly use static variable approach as you are inheriting ApiTest Class from QueryEndpoint Class. Here is the code snippet :
Your QueryEndpoint Class :
package com.example.misc;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.authentication.PreemptiveBasicAuthScheme;
import org.junit.BeforeClass;
public class QueryEndpoint {
static String userName = "username123";
static String password = "password123";
#BeforeClass
public static void setup() {
RestAssured.port = 8010;
PreemptiveBasicAuthScheme authScheme = new PreemptiveBasicAuthScheme();
authScheme.setUserName(userName);
authScheme.setPassword(password);
RestAssured.authentication = authScheme;
String basePath;
basePath = "/api/version1/";
RestAssured.basePath = basePath;
String baseHost;
baseHost = "http://localhost";
RestAssured.baseURI = baseHost;
}
}
Your ApiTest Class :
package com.example.tests;
import com.example.misc.QueryEndpoint;
import org.junit.Test;
import static com.jayway.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
public class ApiTest extends QueryEndpoint{
#Test
public void verifyTopLevelURL() {
given()
.auth(). preemptive().basic(userName, password)
.contentType("application/json")
.when().get("/123456789").then()
.body("fruit",equalTo("123456789"))
.body("fruit.apple",equalTo(37))
.body("fruit.red",equalTo("apple"))
.statusCode(200);
}
You can do same thing with headers too. Hope this helped.
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 5 years ago.
I am not able to #autowire a class in spring boot application. below is the project explorer snapshot:
From my main class CrmDisconnectionApplication, I am calling DisconnectionConTrigger class. In that class I am doing #autowire for YamlConfig. But I am getting null pointer exception.
below is the code:
CrmDisconnectionApplication
package com.wpits.crm.disconnection;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.wpits.crm.disconnection.quartzJob.DisconnectionCronTrigger;
#SpringBootApplication(scanBasePackages = { "com.wpits.crm" })
public class CrmDisconnectionApplication {
public static void main(String[] args) {
SpringApplication.run(CrmDisconnectionApplication.class, args);
DisconnectionCronTrigger disconnectionCronTrigger = DisconnectionCronTrigger.getInstance();
disconnectionCronTrigger.initialize();
}
}
DisconnectionCronTrigger
package com.wpits.crm.disconnection.quartzJob;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wpits.crm.disconnection.config.YamlConfig;
#Component
public class DisconnectionCronTrigger {
#Autowired
private YamlConfig myConfig;
private static DisconnectionCronTrigger obj = null;
private DisconnectionCronTrigger() {}
public static DisconnectionCronTrigger getInstance() {
if(obj == null) {
obj = new DisconnectionCronTrigger();
}
return obj;
}
public void initialize() {
System.out.println("using environment: " + myConfig.getEnvironment());
System.out.println("name: " + myConfig.getName());
System.out.println("servers: " + myConfig.getServers());
System.out.println("hobies: "+myConfig.getHobies());
JobDetail job = JobBuilder.newJob(DisconnectionJob.class).withIdentity("DisconnectionJob", "group1").build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("cronTrigger", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")).build();
try {
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
YamlConfig
package com.wpits.crm.disconnection.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.*;
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties
public class YamlConfig {
private String name;
private String environment;
private List<String> servers = new ArrayList<>();
private List<String> hobies = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEnvironment() {
return environment;
}
public void setEnvironment(String environment) {
this.environment = environment;
}
public List<String> getServers() {
return servers;
}
public void setServers(List<String> servers) {
this.servers = servers;
}
public List<String> getHobies() {
return hobies;
}
public void setHobies(List<String> hobies) {
this.hobies = hobies;
}
}
I am getting null pointer exception for line System.out.println("using environment: " + myConfig.getEnvironment()); in class DisconnectionCronTrigger. Where am I getting it wrong. Please correct me..
The problem is this line
DisconnectionCronTrigger disconnectionCronTrigger = DisconnectionCronTrigger.getInstance();
In getInstance you are creating a new object using new. You should not do new, instead Autowire the bean or get it from Spring application context.
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(CrmDisconnectionApplication.class, args);
DisconnectionCronTrigger disconnectionCronTrigger = (DisconnectionCronTrigger)context.getBean("disconnectionCronTrigger");
disconnectionCronTrigger.initialize();
}
If you do it like this, then you will get an object will all the fields in the bean autowired. If you create a object using new, then you wont.
I have a Spring-boot app.
I want to use variable from application.properties in class method but I have nullPointerException.
Here's a simple example that doesn't work.
application.properties:
#data paths
file.path=C:\\Users\\apodar\\autoTest
Config.java
package com.eserv.autotest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class Config {
#Value("${file.path}")
String filePath;
public String getFilePath() { return filePath; }
public String getScreenshotsPath() {
return getFilePath() + "/screenshots";
}
}
AutotestApplication.java
package com.eserv.autotest;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.Transactional;
#SpringBootApplication(
scanBasePackageClasses = {
AutotestApplication.class,
}
)
public class AutotestApplication implements CommandLineRunner {
#Autowired DataSource dataSource;
public static void main(String[] args) {
SpringApplication.run(AutotestApplication.class, args);
}
#Transactional(readOnly = true)
#Override
public void run(String... args) throws Exception {
System.out.println("DATASOURCE = " + dataSource);
}
}
SeleniumTestExecutionListener:
public class SeleniumTestExecutionListener extends AbstractTestExecutionListener {
#Inject Config config;
private WebDriver webDriver;
#Override
public void afterTestMethod(TestContext testContext) throws Exception {
if (testContext.getTestException() == null) {
return;
}
File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
String testName = toLowerUnderscore(testContext.getTestClass().getSimpleName());
String methodName = toLowerUnderscore(testContext.getTestMethod().getName());
FileUtils.copyFile(screenshot, new File( config.getScreenshotsPath() + testName + "_" + methodName + "_" + screenshot.getName()));
}
}
Why does config.getScreenshotsPath() method doesn't return path. config is null.
Autowiring in a TestExecutionListener will not work. The creation and lifecycle of the TestExecutionListener instances is managed by the Test Context framework of Spring and that isn't part of the ApplicationContext but external. Hence auto wiring will not work.
If you want to use beans in your TestExecutionListener instead retrieve the ApplicationContext from the TestContext.
#Override
public void afterTestMethod(TestContext testContext) throws Exception {
if (testContext.getTestException() == null) {
return;
}
final Config config = testContext.getApplicationContext().getBean(Config.class);
File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
String testName = toLowerUnderscore(testContext.getTestClass().getSimpleName());
String methodName = toLowerUnderscore(testContext.getTestMethod().getName());
FileUtils.copyFile(screenshot, new File( config.getScreenshotsPath() + testName + "_" + methodName + "_" + screenshot.getName()));
}