restlet odata pojo generator errors - java

Using .net tooling, I have been able create an ODATA service endpoint that exposes a legacy MSSQL database. It was my intent to then use odata4j to communicate to it. However, lacking pojos, I turned to restlet. I made all entities visible in the service, but when I run the restlet generator it fails to generate pojos saying:
java.util.concurrent.TimeoutException
at org.restlet.ext.xml.SaxRepresentation.parse(SaxRepresentation.java:230)
at org.restlet.ext.odata.internal.edm.Metadata.<init>(Metadata.java:79)
at org.restlet.ext.odata.Service.getMetadata(Service.java:488)
at org.restlet.ext.odata.Generator.main(Generator.java:137)
...
Can't get the metadata for `http://localhost:53088/ODataService.svc/`
...
java.io.IOException: Couldn't parse the source representation: java.io.IOException: The thread blocked at the cyclic barrier has timed out.
at org.restlet.ext.xml.SaxRepresentation.parse(SaxRepresentation.java:238)
at org.restlet.ext.odata.internal.edm.Metadata.<init>(Metadata.java:79)
at org.restlet.ext.odata.Service.getMetadata(Service.java:488)
at org.restlet.ext.odata.Generator.main(Generator.java:137)
at xxx.model.generator.ModelGenerator.main(ModelGenerator.java:12)
I decided to trim down the ODATA service to a single simple entity and try the code generation and it worked! But as I enabled more entities, I received an XML parsing error:
Can't get the metadata for `http://localhost:53088/ODataService.svc/`
java.io.IOException: Couldn't parse the source representation:\
org.xml.sax.SAXParseException: XML document structures must start and end within \
the same entity.
at org.restlet.ext.xml.SaxRepresentation.parse(SaxRepresentation.java:238)
at org.restlet.ext.odata.internal.edm.Metadata.<init>(Metadata.java:79)
at org.restlet.ext.odata.Service.getMetadata(Service.java:488)
at org.restlet.ext.odata.Generator.main(Generator.java:137)
at xxx.model.generator.ModelGenerator.main(ModelGenerator.java:12)
An error occurred:
Cannot retrieve the metadata.
Anyways, it seems to dislike the xml after some number of entities, rather than disliking a specific entity. Also the XML from http://localhost:53088/ODataService.svc/$metadata is valid with no errors.
Here is the Generator code:
import org.restlet.ext.odata.Generator;
public class ModelGenerator
{
public static final String [] URL_WORKSPACE = { "http://localhost:53088/ODataService.svc/", "src/main/java/"};
public static void main(String[] args)
{
Generator.main(URL_WORKSPACE);
}
}
Here are my maven POM details:
<properties>
<org.odata4j.version>0.7.0</org.odata4j.version>
<org.restlet.version>2.1.4</org.restlet.version>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.odata4j</groupId>
<artifactId>odata4j-core</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet</artifactId>
<version>${org.restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet.ext.odata</artifactId>
<version>${org.restlet.version}</version>
</dependency>
</dependencies>
Any suggestions would be appreciated. Thank you!

Related

How to decode JSon response with custom Feign client?

In my application, I have to know, from a list a server addresses, which are up. The solution I found is to call health endpoint from Spring-Boot Actuator, for each of them. The JSon reponse is:
{
"status": "UP"
}
In other parts of the application, I use Feign clients from Spring-Cloud defined with the #FeignClient annotation, which works perfectly:
#FeignClient(
name = "tokenProxy",
url = "${host}:${port}"
)
Unfortunately this kind of configuration doesn't allow to re-use the same client to call the same endpoint on different addresses. So I have to define my own custom client (If there is another solution, do not hesitate to tell me! ):
#GetMapping(
value = "/servers"
)
public Server discover() {
MyClient myClient = Feign.builder()
.target(
Target.EmptyTarget.create(
MyClient.class
)
);
return myClient.internalPing(URI.create("http://localhost:8090"));
}
interface MyClient {
#RequestLine("GET /actuator/health")
Server internalPing(URI baseUrl);
}
class Server {
private final String status;
#JsonCreator
public Server(#JsonProperty("status") String status) {
this.status = status;
}
public String getStatus() {
return status;
}
}
When I call the endpoint /servers, I get the following error, indicating that my custom Feign client isn't confgured with the appropriate decoder:
feign.codec.DecodeException: class com.xxx.web.Server is not a type supported by this decoder.
at feign.codec.StringDecoder.decode(StringDecoder.java:34) ~[feign-core-10.10.1.jar:na]
at feign.codec.Decoder$Default.decode(Decoder.java:92) ~[feign-core-10.10.1.jar:na]
at feign.AsyncResponseHandler.decode(AsyncResponseHandler.java:115) ~[feign-core-10.10.1.jar:na]
at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:87) ~[feign-core-10.10.1.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) ~[feign-core-10.10.1.jar:na]
I guess i should use JacksonDecoder, but I cannot find it in my dependencies from Spring-Cloud Hoxton.SR5:
<dependencies>
...
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
...
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
Could someone help me, either with a better solution for my need or a explanation on how to properly configure custom Feign clients?
Thanks in advance
In fact, the library which includes Jackson decoder and encoder was not loaded by default when using spring-cloud dependencies. To fix the issue I simply had to add the following to my pom.xml file:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
Another way could be annotating the class with #Import(FeignClientsConfiguration.class) which is the default configuration provided by Spring Cloud Netflix.
Then it becomes easy to inject both Encoder and Decoder when creating the Feign client:
#Import(FeignClientsConfiguration.class)
#Configuration
public class MyConfiguration {
(...)
Myclient myClient (Decoder feignDecoder, Encoder feignEncoder) {
return Feign.builder()
.decoder( feignDecoder )
.encoder( feignEncoder )
.target(
Target.EmptyTarget.create(
MyClient.class
)
);
}
There are two different defined encoders in the configuration class (pageable or not), so pay attention to clearly identify which you want, either by its name or a qualifier.

Can't import org.springframework.mock.web.MockMultipartFile outside of testing classes

I'm trying to turn an image stored as a Blob in my DB into a MultipartFile to serve back to the client when it's requested. I retrieve the Blob as a byte[] and I'm trying to convert it into a MultipartFile to serve back to the client
I'm trying to do it this way : https://stackoverflow.com/a/25820543/7082628
But IntelliJ is telling me it can't find the MockMultipartFile part when I do the import of: import org.springframework.mock.web.MockMultipartFile
I can import this in a test class no problem, but not outside of the test class. Can I do it here?
Also, I tried to do this by implementing a class with my own version of MultipartFile as stated in another popular answer, but it's telling me it can't find a serialzer.
Any suggestions?
There are couple of issues with your approach.
Multipart file is an HTTP Request format and not intended for response.
For a response all you have to do is write the file to the response.getOutputStream(). Which becomes way easier using Spring
Now coming to your original question that you can't import MockMultipartFile. That's most likely because you're using Maven and the dependency (most likely spring-boot-starter-test) has scope set to test.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope><!-- CHANGE THIS TO "runtime" -->
</dependency>
But again as I said before, there's no need to do that. You don't have to consider the Multipart when you're providing a response, it's a protocol to upload files.
Here's how you can provide a download link to a Blob in Spring
#GetMapping(path = "download")
public ResponseEntity<Resource> download(String param) throws IOException {
InputStreamResource resource = new InputStreamResource(/* InputStream of blob */);
long fileLength = /*Length of content, bytes.length or something */
return ResponseEntity.ok()
.contentLength(fileLength)
.contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE)
.body(resource);
}
Finally the package i found which helped with
import org.springframework.mock.web.MockMultipartFile;
<properties>
<java.version>1.8</java.version>
<spring.version>5.1.2.RELEASE</spring.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>

Google Cloud dataflow dropping messages

I have the following application that runs a data pipeline and listens to Google pubsub:
Config:
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-sdks-java-core</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-google-cloud-dataflow-java</artifactId>
<version>2.0.0</version>
</dependency>
Code:
Pipeline p = //Initialise pipeline
p.apply("read messages", readMessage())
.apply("log message", logMessage())
private static PubsubIO.Read<String> readMessage() {
return PubsubIO.readStrings()
.fromSubscription("my_subscription");
}
//Log message just logs the message
I faced an issue where messages were getting dropped intermittently (i.e. they were not making it to dataflow pipeline from pubsub). In order to debug, I wrote another application and made it listen to the same pubsub. Below is the config:
Config:
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-pubsub</artifactId>
<version>0.22.0-beta</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-pubsub</artifactId>
<version>v1-rev358-1.22.0</version>
</dependency>
Code:
#Component
public class PubsubMessageReceiver implements MessageReceiver{
private static Logger logger = LoggerFactory.getLogger(PubsubMessageReceiver.class);
#Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
logger.info(message.getData().toStringUtf8());
consumer.ack();
}
}
I made it run for a couple of hours (by creating a new subscription to listen to the same topic as the original application), checked the log files and found some messages that did not make it to the dataflow pipeline.
Now, this is intermittent and I am not able to reproduce it (even with load testing). Does this have anything to do with google's beam libraries (looks like a race condition or similar)? If yes, does anyone know if this can be fixed by changing the configuration/updating the version?

Restful WebService call with Jersey client version 2.2

CASE
I am trying to fetch User data to Servlet filter using REST service.
POM.xml
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
CODE
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Client client = ClientBuilder.newClient(new ClientConfig());
String entity = client.target("http://localhost:8080/insame/webresources/com.insame.entity.users")
.path("count")
.request(MediaType.TEXT_PLAIN)
.get(String.class);
System.out.println("entity-------->" +entity);
REST:
#GET
#Path("count")
#Produces("text/plain")
public String countREST() {
return String.valueOf(super.count());
}
PROBLEM
javax.ws.rs.ProcessingException: java.net.SocketException: Unexpected end of file from server
at org.glassfish.jersey.client.HttpUrlConnector.apply(HttpUrlConnector.java:202)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:215)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:650)
WARNING: StandardWrapperValve[com.insame.service.ApplicationConfig]: Servlet.service() for servlet com.insame.service.ApplicationConfig threw exception
javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:904)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:749)
at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:88)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:650)
QUESTION
0) What is wrong in my code?
1) What is the wisest way to fetch data from servlet filter using
REST + JPA?
2) If there is another way to do this, better I mean,
pls let me know?
3) Is the Jersey Client the only way
4) How can I
get EntityManager and call the rest service straight from filter
without Jersey Client?
Jersey documentation and examples:
http://jersey.java.net/documentation/latest/user-guide.html#d0e2481
Thanks,
Sami
0) 500 error code means there is some thing wrong on Server side. May be the action action threw some error even though REST got processed.
1) for simple REST, I have used Restlet and HttpClient. Even jerseyClient with JAXB to process response as POJOs. In my experience, simple HTTP is the best and simplest way to process REST response. You can easily write a wrapper on http code (java.net) to process request/response, create Dom around that
2) and 3) are answered above

Post data Spring web services Restful

I am trying to save data on my database with a web service POST wich serializes a HTML form to save a object. The rest client firefox says this:
"The server refused this request because the requested entity is in a format not supported by the requested resource for the requested method"
The eclipse console shows the message:
org.jasig.cas.client.util.CommonUtils - safeGetParameter called on a POST HttpServletRequest for LogoutRequest. Cannot complete check safely. Reverting to standard behavior for this Parameter
I understand that the object that i want to save is not valid, but I don't see what the problem is.
#RequestMapping(value="/solicitudCita", method = RequestMethod.POST)
public #ResponseBody String putSolicitud(#ModelAttribute("Solicitud") Solicitud solicitud) throws Exception{
System.out.println(solicitud.toString());
solicitudCitaAppMService.createOrUpdate(solicitud);
String solicitudAdded = "Solicitud de cita -> {" + solicitud.toString() + "} aƱadida";
System.out.println(solicitud);
return solicitudAdded;
}
Help me please
Thanks
If you want to call this controller in a RESTful manner, you have to annotate the solicitud parameter as #RequestBody. Second, you have to have the Jackson libraries in you classpath so Spring can pick them up and use them for unmarshalling the object.
If you use Maven, use these dependencies:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
</dependency>
BTW, why do you have to serialize the HTML form and sent it across? I would suggest you use a REST client, for instance this one, that is available in the Chrome WebStore.

Categories