I'm trying to create and test an API endpoint using AWS Lambda and API Gateway. I can test my function successfully using Lambda Test, but when I try to test my endpoint it gives:
{
"message": "Internal server error"
}
This is my handler class:
package com.amazonaws.lambda.gandhi.conversion.api;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.RandomStringUtils;
import com.amazonaws.lambda.gandhi.conversion.api.Response.AuthClientCredentialResponse;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.lambda.gandhi.conversion.api.utils.ClientAuthPOJO;
public class AuthClientCredentialServiceHandler implements RequestHandler<ClientAuthPOJO, Object> {
private AuthClientCredentialResponse authClientCredentialResponse;
private static final SecureRandom RANDOM = new SecureRandom();
public static int MAX_CLIENT_KEY = 10;
public static int CLIENT_SECRET_LENGTH = 69;
#Override
public AuthClientCredentialResponse handleRequest(ClientAuthPOJO clientIdSecret, Context context) {
String clientSecret;
try {
context.getLogger().log("Input: "
+ clientIdSecret);
String clientId = clientIdSecret.getClientId();
clientSecret = generateClientSecretKey();
Map<String, String> clientCredsMap = getClientCredentials();
if (clientCredsMap.size() > MAX_CLIENT_KEY) {
throw new RuntimeException(String.format("Max limit is %d, Please delete some keys", MAX_CLIENT_KEY));
}
clientCredsMap.forEach((k, v) -> {
if (clientId.equals(k)) {
throw new RuntimeException("Client Already exists");
}
});
storeClientCredentials(clientId, clientSecret);
AuthClientCredentialResponse authClientCredentialResponse = AuthClientCredentialResponse.builder().success(
true).clientId(clientId).clientSecret(clientSecret).build();
this.authClientCredentialResponse = authClientCredentialResponse;
} catch (Exception e) {
throw new RuntimeException(
"Failed to generate client secret: "
+ e.getMessage());
}
return authClientCredentialResponse;
}
private String generateClientSecretKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
String clientSecret = RandomStringUtils.randomAlphanumeric(CLIENT_SECRET_LENGTH);
System.out.printf("clientSecret: %s%n", clientSecret);
return clientSecret;
}
private void storeClientCredentials(String clientId, String clientSecret) throws IOException {
/*
* TODO:
* Some logic to store clientCredentials to a file or DB. Decide later.
*/
System.out.println("temp ClientCredentials stored");
}
public Map<String, String> getClientCredentials() throws IOException {
/*
* TODO:
* Some logic to fetch clientCredentials from file or DB. Decide later.
*/
Map<String, String> clientCredMap = new HashMap<String, String>();
clientCredMap.put("1", "secretKey1");
clientCredMap.put("2", "secretKey2");
clientCredMap.put("3", "secretKey3");
clientCredMap.put("4", "secretKey4");
return clientCredMap;
}
}
My input class:
package com.amazonaws.lambda.gandhi.conversion.api.utils;
public class ClientAuthPOJO {
String clientId;
String clientSecret;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public ClientAuthPOJO(String clientId, String clientSecret) {
super();
this.clientId = clientId;
this.clientSecret = clientSecret;
}
public ClientAuthPOJO() {
}
}
My test object in lambda:
My test for endpoint in API Gateway:
Can someone please help me figure out the problem in creating the function or API Gateway?
Edit:
When I check the logs, I found that the parameters to the functions (clientId and clientSecret) are null. So there seems to be some problem in the way I'm sending my request body.
Related
Google Cloud and to PubSub Service.
I have implemented a simple CustomAttributeReceiver in the lines of below sample code
https://github.com/googleapis/java-pubsub/blob/master/samples/snippets/src/main/java/pubsub/PublishWithCustomAttributesExample.java
How ever i am getting the below exception
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected STRING but was BEGIN_OBJECT at path $ at com.google.gson.Gson.fromJson(Gson.java:944) at
com.google.gson.Gson.fromJson(Gson.java:1003) at
com.google.cloud.functions.invoker.NewBackgroundFunctionExecutor$TypedFunctionExecutor.serviceLegacyEvent(NewBackgroundFunctionExecutor.java:257) at
com.google.cloud.functions.invoker.NewBackgroundFunctionExecutor.serviceLegacyEvent(NewBackgroundFunctionExecutor.java:343) at
Can someone throw light on what i am missing here?
Publisher side
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.api.core.ApiFuture;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.TopicName;
import PubSubMessage;
TopicName topicName = TopicName.of(projectId, topicId);
System.out.println("informListenersAboutSucessfulRegisteration=" + topicName);
Publisher publisher = null;
try {
publisher = Publisher.newBuilder(topicName).build();
PubSubMessage newUserRegisterMsg = new PubSubMessage();
Map<String, String> attributes = new HashMap<String, String>();
attributes.put(PubSubMessage.newUserLanguage, newUserLanguage);
newUserRegisterMsg.setAttributes(attributes);
ByteString data = ByteString.copyFromUtf8("NewUserRegisteration");
PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).putAllAttributes(attributes).build();
ApiFuture<String> messageIdFuture = publisher.publish(pubsubMessage);
String messageId = messageIdFuture.get();
System.out.println("Published message ID: " + messageId);
} catch (Exception e) {
Logger.getLogger(PubSubMessenger.name).log(Level.SEVERE, "Exception while publishing message", e);
} finally {
if (publisher != null) {
publisher.shutdown();
publisher.awaitTermination(1, TimeUnit.MINUTES);
}
}
Receiver side
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import com.google.cloud.functions.BackgroundFunction;
import com.google.cloud.functions.Context;
import PubSubMessage;
public class SendEmailFromSendGrid implements BackgroundFunction<PubSubMessage> {
public SendEmailFromSendGrid() {
}
public void accept(PubSubMessage message, Context context) throws Exception {
System.out.println("invoked accept");
String name = "World";
if (message != null && message.getData() != null) {
name = new String(Base64.getDecoder().decode(message.getData().getBytes(StandardCharsets.UTF_8)),
StandardCharsets.UTF_8);
}
System.out.println(String.format("Hello %s!", name));
return;
}
}
PubSubMessage Definition
import java.util.Map;
public class PubSubMessage {
public static final String newUserLanguage = "userLanguage";
private String data;
private Map<String, String> attributes;
private String messageId;
private String publishTime;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public String getPublishTime() {
return publishTime;
}
public void setPublishTime(String publishTime) {
this.publishTime = publishTime;
}
}
THANK YOU
This answer was provided by #user1241724 in the comment section:
Redid the whole exercise and it is working now. Only difference is
added default constructor in PubSubMessage.
I was trying to mock a private method's output which is being called inside another private method, I have no choice but to test the later private method, so I have added sample test code which I can represent here,
This Sample Class
package com.testableClass;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class TestableClass {
private int initialMockMethod(Object obj)
{
System.out.println(" ++++ Came Here ++++ ");
String str = getRestString("");
System.out.println("str ="+str);
return str.length();
}
private String getRestString(String abc)
{
String output="";
try {
URL url = new URL("https://gorest.co.in/public-api/users");//your url i.e fetch data from .
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP Error code : "
+ conn.getResponseCode());
}
InputStreamReader in = new InputStreamReader(conn.getInputStream());
BufferedReader br = new BufferedReader(in);
while ((output = br.readLine()) != null) {
System.out.println(output);
}
conn.disconnect();
return output;
} catch (Exception e) {
System.out.println("Exception in NetClientGet:- " + e);
}
return abc;
}
}
Now This PowerMock Class
package com.testableClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import junit.framework.Assert;
#RunWith(PowerMockRunner.class)
#PrepareForTest(fullyQualifiedNames = "com.testableClass.TestableClass")
public class PowerMockTest {
#Test
public void testPrivateMethod() throws Exception
{
String message = "Hello PowerMockito";
String expectation = "Expectation";
TestableClass mock = PowerMockito.spy(new TestableClass());
// PowerMockito.doReturn(expectation).when(mock, "getRestString", message);
PowerMockito.when(mock, "getRestString", message).thenReturn(expectation);
int count = Whitebox.invokeMethod(mock, "initialMockMethod", new Object());
System.out.println(" +++ Count : "+count+" ++++ ");
Assert.assertTrue(true);
}
}
my issue is when I am running my test case then
PowerMockito.when(mock, "getRestString", message).thenReturn(expectation);
executes original method and returns original output while my requirement is that,
when my test case is actually calling private method initialMockMethod it should not call getRestString instead of that it should return my mocked expected output which is "Expectation"
Instead of using reflection and PowerMock, I'd say that do not try to mock a private method. It is a hidden detail of the class.
What I suggest is that, if your method makes an HTTP request, then let it do that. But you can use a mock server to mock the response. But to do that, you need to make your endpoint external, so that it can be injected.
I changed your class a little bit; still the same purpose tho.
public class TestableClass {
private final String resourceUrl;
public TestableClass(String resourceUrl) {
this.resourceUrl = resourceUrl;
}
public int publicMethod() {
return initialMockMethod(null);
}
private int initialMockMethod(Object obj) {
var str = getRestString("");
return str.length();
}
private String getRestString(String abc) {
try {
var url = new URL(resourceUrl);
var conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP Error code : "
+ conn.getResponseCode());
}
var in = new InputStreamReader(conn.getInputStream());
var br = new BufferedReader(in);
var result = br.lines().collect(Collectors.joining("\n"));
conn.disconnect();
return result;
} catch (Exception e) {
System.out.println("Exception in NetClientGet:- " + e);
}
return abc;
}
}
and here's the test
public class TestingTestableClass {
#Test
#SneakyThrows
public void test() {
final var server = new MockWebServer();
server.start(9999);
var instance = new TestableClass("http://127.0.0.1:9999");
server.enqueue(
new MockResponse()
.setResponseCode(200)
.setBody("this is the response")
);
final int result = instance.publicMethod();
Assertions.assertEquals(
"this is the response".length(),
result
);
final var record = server.takeRequest();
final var method = record.getMethod();
Assertions.assertEquals("GET", method);
server.shutdown();
}
}
Check out MockWebServer here
My organization is running spring boot app on AWS ECS docker container which reads the credentials for Postgres sql from secrets manager in AWS during boot up. AS part of security complaince, we are rotating the secrets every 3 months. The spring boot app is loosing connection with the database and going down when the RDS credentials are rotated.we have to restart it in order to pick the new credentials to work properly. Is there any way I can read the credentials automatically once the credentials are rotated to avoid restarting the application manually?
After some research I found that the postgres database in AWS supports passwordless authentication using IAM roles. We can generate a token which is valid for 15 mins and can connect to database using that token. I prefer this way of connecting to database rather than using password for my database. More details about setting up password less authentication can be found here
Code example as below
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.services.rds.auth.GetIamAuthTokenRequest;
import com.amazonaws.services.rds.auth.RdsIamAuthTokenGenerator;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.jdbc.pool.ConnectionPool;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.Properties;
public class RdsIamAuthDataSource extends org.apache.tomcat.jdbc.pool.DataSource {
private static final Logger LOGGER = LoggerFactory.getLogger(RdsIamAuthDataSource.class);
private static final int DEFAULT_PORT = 5432;
private static final String USESSL = "useSSL";
private static final String REQUIRE_SSL = "requireSSL";
private static final String BOOLEAN_TRUE = "true";
private static final String VERIFY_SERVER_CERTIFICATE = "verifyServerCertificate";
private static final String THREAD_NAME = "RdsIamAuthDataSourceTokenThread";
/**
* Constructor for RdsIamAuthDataSource.
* #param props {#link PoolConfiguration}
*/
public RdsIamAuthDataSource(PoolConfiguration props) {
this.poolProperties = props;
}
#Override
public ConnectionPool createPool() throws SQLException {
if (pool == null) {
return createPoolImpl();
} else {
return pool;
}
}
protected ConnectionPool createPoolImpl() throws SQLException {
synchronized (this) {
return pool = new RdsIamAuthConnectionPool(poolProperties);
}
}
private class RdsIamAuthConnectionPool extends ConnectionPool implements Runnable {
private RdsIamAuthTokenGenerator rdsIamAuthTokenGenerator;
private String host;
private String region;
private int port;
private String username;
private Thread tokenThread;
/**
* Constructor for RdsIamAuthConnectionPool.
* #param prop {#link PoolConfiguration}
* #throws SQLException {#link SQLException}
*/
public RdsIamAuthConnectionPool(PoolConfiguration prop) throws SQLException {
super(prop);
}
#Override
protected void init(PoolConfiguration prop) throws SQLException {
try {
final URI uri = new URI(prop.getUrl().substring(5));
this.host = uri.getHost();
this.port = uri.getPort();
if (this.port < 0) {
this.port = DEFAULT_PORT;
}
this.region = StringUtils.split(this.host,'.')[2];
this.username = prop.getUsername();
this.rdsIamAuthTokenGenerator = RdsIamAuthTokenGenerator.builder()
.credentials(new DefaultAWSCredentialsProviderChain())
.region(this.region)
.build();
updatePassword(prop);
final Properties props = prop.getDbProperties();
props.setProperty(USESSL, BOOLEAN_TRUE);
props.setProperty(REQUIRE_SSL, BOOLEAN_TRUE);
props.setProperty(VERIFY_SERVER_CERTIFICATE, BOOLEAN_TRUE);
super.init(prop);
this.tokenThread = new Thread(this, THREAD_NAME);
this.tokenThread.setDaemon(true);
this.tokenThread.start();
} catch (URISyntaxException e) {
LOGGER.error("Database URL is not correct. Please verify", e);
throw new RuntimeException(e.getMessage());
}
}
/**
* Refresh the token every 12 minutes.
*/
#Override
public void run() {
try {
while (this.tokenThread != null) {
Thread.sleep(12 * 60 * 1000);
updatePassword(getPoolProperties());
}
} catch (InterruptedException e) {
LOGGER.error("Background token thread interrupted", e);
}
}
#Override
protected void close(boolean force) {
super.close(force);
final Thread thread = tokenThread;
if (thread != null) {
thread.interrupt();
}
}
private void updatePassword(PoolConfiguration props) {
final String token = rdsIamAuthTokenGenerator.getAuthToken(GetIamAuthTokenRequest.builder()
.hostname(host)
.port(port)
.userName(this.username)
.build());
LOGGER.info("Updated IAM token for connection pool");
props.setPassword(token);
}
}
}
Supply the following DataSource as a spring bean. That's it. Now your application will automatically refresh credentials every 12 minutes
#Bean
public DataSource dataSource() {
final PoolConfiguration props = new PoolProperties();
props.setUrl("jdbc:postgresql://myapp.us-east-2.rds.amazonaws.com/myschema?ssl=true");
props.setUsername("rdsadminuser");
props.setDriverClassName("org.somedatabase.Driver");
return new RdsIamAuthDataSource(props);
}
I am a straight up newbie. After 2 weeks of research, I've arrived at this point, still very lost and desperate.
My goal: Retrieve data from EnergyStar Portfolio Manager Restful web services / API and put that data into a SQL database or an excel worksheet.
Progress so far:
1) I found an example code that seems like it would fit what I need well, except for the authentication part. I am more successful at getting WSDL services to work than RESTful services. Particularly for EnergySTAR, requiring some kind of authentication, which I can't seem to get around to.
2) The retrieve GET protocol: http://portfoliomanager.energystar.gov/webservices/home/test/api/reporting/designMetrics/get
My source code:
package com;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import com.User;
#Path("/wstest/property/")
public class UserManagementModule
{
#GET
#Path("/{propertyId}/design/metrics?measurementSystem=METRIC")
#Produces("application/xml")
public Response getUserById(#PathParam("propertyId") Integer id)
{
User user = new User();
user.setId(id);
return Response.status(200).entity(user).build();
}
}
package com;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "propertyMetrics")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#XmlAttribute(name = "propertyId")
private int propertyId;
#XmlElement(name="metric")
private double metric;
#XmlAttribute(name = "designEnergyCost")
private double designEnergyCost;
#XmlAttribute(name = "designScore")
private double designScore;
#XmlAttribute(name = "designSiteTotal")
private double designSiteTotal;
#XmlAttribute(name = "designSiteIntensity")
private double designSiteIntensity;
#XmlAttribute(name = "designTargetEnergyCost")
private double designTargetEnergyCost;
#XmlAttribute(name = "designTargetTotalGHGEmissions")
private double designTargetTotalGHGEmissions;
#XmlAttribute(name = "designTargetSiteTotal")
private double designTargetSiteTotal;
#XmlAttribute(name = "designTargetSiteIntensity")
private double designTargetSiteIntensity;
#XmlAttribute(name = "designTargetSourceTotal")
private double designTargetSourceTotal;
#XmlAttribute(name = "designTargetSourceIntensity")
private double designTargetSourceIntensity;
#XmlAttribute(name = "medianEnergyCost")
private double medianEnergyCost;
#XmlAttribute(name = "medianTotalGHGEmissions")
private double medianTotalGHGEmissions;
#XmlAttribute(name = "medianScore")
private double medianScore;
public int getId() {
return propertyId;
}
public void setId(int propertyId) {
this.propertyId = propertyId;
}
public double getmendianScore() {
return medianScore;
}
//
// public void setFirstName(String firstName) {
// this.firstName = firstName;
// }
// public String getLastName() {
// return lastName;
// }
// public void setLastName(String lastName) {
// this.lastName = lastName;
// }
}
package tests;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import com.User;
public class RestClientXML {
public static void main(String[] args)
{
try
{
URL url = new URL(" https://portfoliomanager.energystar.gov/wstest/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/xml");
if (conn.getResponseCode() != 200)
{
throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String apiOutput = br.readLine();
System.out.println(apiOutput);
conn.disconnect();
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
User user = (User) jaxbUnmarshaller.unmarshal(new StringReader(apiOutput));
System.out.println(user.getId());
/* System.out.println(user.getFirstName());
System.out.println(user.getLastName());
*/
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
I'm know there is some authentication that needs username and pw,so I also tried this piece instead of the RestClient class, but neither works.
public static void main(String[] args) {
CloseableHttpClient httpClient = null;
HttpPost httpPost = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClients.createDefault();
httpPost = new HttpPost("https://portfoliomanager.energystar.gov/wstest/");
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("content-type", "application/xml"));
StringEntity input = new StringEntity("{\"username\": \"yungv1\",\"password\": \"dummypassword\"}");
input.setContentType("application/xml");
httpPost.setEntity(input);
for (NameValuePair h : nvps)
{
httpPost.addHeader(h.getName(), h.getValue());
}
response = httpClient.execute(httpPost);
if (response.getStatusLine().getStatusCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(response.getEntity().getContent())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
response.close();
httpClient.close();
}catch(Exception ex) {
ex.printStackTrace();
}
}
I know it's very sloppy. Can you please point the direction on how I can achieve my goal?
I also tried to run this, and keep getting the 401 errors, which I imagined the authentication fails. I don't know how else to trouble shoot this part and whether there's more thing I need to look into.
conn.setRequestProperty("Authorization", "Basic " + Base64.encodeBase64String((getWebServicesUsername() + ":" + getWebServicesPassword()).getBytes()));
Where conn is HttpURLConnection.
I have created web service using Spring-WS. When I send a request to the web service, this is the response I get in soap-ui:
enter code here
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns2:SendResponse xmlns:ns2="http://mycompany.com/schema/">
<ns2:SendResult>
<ns2:Token>A00179-02</ns2:Token>
</ns2:SendResult>
</ns2:SendResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Is there any way to get rid of the "ns2" namespace prefix from the response? I tried a couple of options:
1) Manually updated package-info.java to set the prefix to "":
#XmlSchema(namespace = "http://mycompany.com/schema/",
xmlns = {
#XmlNs(namespaceURI = "http://mycompany.com/schema/", prefix = "")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.example.foo.jaxb;
2) Set the prefix to "" in the QName object in the endpoint class:
return new JAXBElement<SendAndCommitResponse>(new QName("http://mycompany.com/schema/",
"SendResponse",""), SendResponse.class, response);
Both didn't work. How to get rid off the "ns2" namespace prefix?
I eventually found a solution for this.
My problem was caused by JDK 6 not shipping a full version of rt.jar (http://www.oracle.com/technetwork/java/javase/compatibility-137541.html).
I added the following to my maven config
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.6</version>
</dependency>
And then added
#XmlSchema(namespace = "http://mycompany.com/schema/",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.UNQUALIFIED).
In the package-info.java (like suggested by #acdcjunior above)
I tried a few of the approaches discussed here, but nothing worked...
Below Class from the link - https://zhuanlan.zhihu.com/p/35298171 fixed my issue
Added the below interceptor to remove the namespaces -
public class PayloadPrefixInterceptor extends TransformerHelper implements EndpointInterceptor {
public static final String NAMESPACE = ObjectFactory.class.getPackage().getAnnotation(XmlSchema.class).namespace();
public static final String XMLNS = "xmlns:";
#Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
return true;
}
#Override
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
WebServiceMessage response = messageContext.getResponse();
Source payloadSource = response.getPayloadSource();
DOMResult result = new DOMResult();
transform(payloadSource, result);
removePrefix(result.getNode());
transform(new DOMSource(result.getNode()), response.getPayloadResult());
return true;
}
private void removePrefix(Node node) {
if (node == null) {
return;
}
if (node.getNodeType() == Node.ELEMENT_NODE) {
removeNamespaceDeclaration(node);
}
if (node.getPrefix() != null) {
node.setPrefix(null);
}
NodeList childNodes = node.getChildNodes();
if (childNodes != null) {
IntStream.of(0, childNodes.getLength()).forEach(index -> removePrefix(childNodes.item(index)));
}
Node nextSibling = node.getNextSibling();
if (nextSibling != null) {
removePrefix(nextSibling);
}
}
private void removeNamespaceDeclaration(Node node) {
NamedNodeMap attributes = node.getAttributes();
IntStream.range(0, attributes.getLength()).forEach(index -> {
Node attribute = attributes.item(index);
if (StringUtils.startsWith(attribute.getNodeName(), XMLNS) &&
StringUtils.equals(attribute.getNodeValue(), NAMESPACE)) {
attributes.removeNamedItemNS(attribute.getNamespaceURI(), attribute.getLocalName());
}
});
}
#Override
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
return true;
}
#Override
public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {
}
}
Registered the interceptor using below -
#EnableWs
#Configuration
public class Config extends WsConfigurerAdapter {
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(new PayloadPrefixInterceptor());
super.addInterceptors(interceptors);
}
}
it was hard
first: create a class that intercepts soap request and responses:
package examples.webservices.handler;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class CorrigirConteudoRequisicaoSOAP implements SOAPHandler<SOAPMessageContext> {
public Set<QName> getHeaders() {
return Collections.emptySet();
}
public boolean handleMessage(SOAPMessageContext messageContext) {
this.corrigirConteudoRequisicaoSOAP(messageContext);
return true;
}
private void corrigirConteudoRequisicaoSOAP(SOAPMessageContext messageContext){
SOAPMessage msg = messageContext.getMessage();
try {
NodeList childNodes = msg.getSOAPBody().getChildNodes();
for(int k = 0; k < childNodes.getLength(); k++){
Node item = childNodes.item(k);
String localName = item.getLocalName();
{
item.setPrefix("");
Method m = SOAPElement.class.getDeclaredMethod("setElementQName", QName.class);
//I was forced to use reflection because the method setElementQname is not //visible, neither the class that implements it
m.invoke(item, new QName("", item.getLocalName()));
msg.saveChanges();
}
}
} catch (Exception e) {
try {
msg.writeTo(System.out);
} catch (Exception e1) {
e1.printStackTrace();
}
System.out.println();
}
}
public boolean handleFault(SOAPMessageContext messageContext) {
return true;
}
public void close(MessageContext messageContext) {
}
public static void main(String[] args)throws Exception {
}
}
second: associate the service to soap handle
public class PortalFornecedor {
public Usuario getUsuario(){
XIF367Afae09A3344Fbf2E1De819D6EcbaService classeComNomeFeio = new XIF367Afae09A3344Fbf2E1De819D6EcbaService();
Usuario service = classeComNomeFeio.getHTTPPort();
BindingProvider bp = (BindingProvider)service;
Map<String, Object> requestContext = bp.getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, "user");
requestContext.put(BindingProvider.PASSWORD_PROPERTY, "pass");
this.handle(service);
return service;
}
public Object getDashboard(){
return "";
}
// here we associate the service to soap handle
private BindingProvider handle(Usuario service) {
BindingProvider bp = (BindingProvider)service;
#SuppressWarnings("rawtypes")
List<Handler> chain = new ArrayList<Handler>();
chain.add(new CorrigirConteudoRequisicaoSOAP());
bp.getBinding().setHandlerChain(chain);
return bp;
}
public static void main(String[] args) {
PortalFornecedor pf = new PortalFornecedor();
Usuario usuario = pf.getUsuario();
LoginExecutarIN in = new LoginExecutarIN();
generated.Usuario user = new generated.Usuario();
user.setLogin("onias");
user.setSenha("12345");
user.setCodigoUsuario(0);
in.setParametroEntrada(user);
try {
LoginExecutarOUT out = usuario.loginExecutar(in);
// SOAPMessageContext.getMessage();
System.out.println(out.getRegistroSelecionado().getNome());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is the simple and easiest solution for that problem. Create Package-Info.Java file in your model package and add the below script to that.
#javax.xml.bind.annotation.XmlSchema(namespace = "http://mycompany.com/schema", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, xmlns = { #javax.xml.bind.annotation.XmlNs(namespaceURI = "http://mycompany.com/schema", prefix = "") })
package my.com.scicom.stars.model;
And add elementFormDefault as "qualified" in your xsd or wsdl file.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://mycompany.com/schema"
targetNamespace="http://mycompany.com/schema"
elementFormDefault="qualified">