I am creating a webserver on my Android device, and everything seems to be working fine except for the fact Jackson is not converting my objects to JSON. When I make a successfull (200) HTTP request from the browser on my Android device I am getting no JSON data in the network tab (Looking at the response in Google Chrome). I have registered the Jackson Converter as the documents state, and as what previous StackOverflow questions have covered. This does not seem to work, and I'm not getting any error. Any idea what I'm doing wrong? I hope this is enough information for you geniuses here, otherwise let me know what else you guys need.
Note I also tried GSONConverter
Edit: I've noticed that the entity inside the response is always null
WebServer.java
package com.android.restlettest;
import org.restlet.Component;
import org.restlet.data.Protocol;
public class WebServer {
Component component;
WebServer() {
component = new Component();
component.getServers().add(Protocol.HTTP, 9001);
component.getDefaultHost().attach("", new MyApplication());
}
void start() {
try {
System.out.println("Starting the WebServer");
component.start();
} catch(Exception e) {
System.out.println("Exception caught: " + e);
}
}
void stop() {
}
}
MyApplication.java
package com.android.restlettest;
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;
import org.restlet.engine.Engine;
import org.restlet.ext.gson.GsonConverter;
import org.restlet.ext.jackson.JacksonConverter;
public class MyApplication extends Application {
MyApplication() {
super();
Engine.getInstance().getRegisteredConverters().add(new JacksonConverter());
//Engine.getInstance().getRegisteredConverters().add(new GsonConverter());
}
#Override
public synchronized Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/", IndexResource.class);
router.attach("/report/log", LogServerResource.class);
return router;
}
}
LogServerResource.java
public class LogServerResource extends ServerResource implements ILogResource {
#Get("json")
public Log retrieve() {
Log[] list = new Log[2];
Log log1 = new Log("test.log", "alksdjf32984u23jfsdv", 0);
list[0] = log1;
return list[0];
//return "{\"resource\": \"log\"}";
}
}
Log.java
package com.android.restlettest;
import java.io.Serializable;
public class Log implements Serializable {
private static final long serialVersionUID = 1L;
public String data;
public String name;
public int id;
public Log() {
}
public Log(final String name, final String data, final int id) {
super();
this.name = name;
this.data = data;
this.id = id;
}
}
I ended up finding someone that had a similar issue to me. I was missing some libs that needed to be added. I apologize for wasting your time.
Restlet server on Android: client is getting a null object
Related
I am new to spring boot, I want to post the data(let's say question data) using a static list without using database and repository, but i can't understand how to solve it.
This my controller class
#PostMapping
public ResponseEntity<Object> createQuestion(#Valid #RequestBody CreateQuestionCommand command) {
var query = new FindQuestionByIdTemp(command.getId());
var response = queryGateway.query(query, ResponseTypes.instanceOf(Object.class)).join();
if (response != null) {
return new ResponseEntity<>(new QuestionCreatedResponse(command.getId(),"This id is already associated with other question"), HttpStatus.INTERNAL_SERVER_ERROR);
}
try {
commandGateway.send(command);
return new ResponseEntity<>(new QuestionCreatedResponse(command.getId(), "Question Created successfully!"), HttpStatus.CREATED);
} catch (Exception e) {
var safeErrorMessage = "Error while processing create question request for id - " + command.getId();
System.out.println(e.toString());
return new ResponseEntity<>(new QuestionCreatedResponse(command.getId(), safeErrorMessage), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
CreateQuestionCommandClass
public class CreateQuestionCommand {
#AggregateIdentifier
private String id;
private Questions question;
}
Questions Class
public class Questions {
#Id
private String id;
private String title;
private String label;
private String feedback;
}
This is an AggregateClass
#Aggregate
public class QuestionAggregateClass {
#AggregateIdentifier
private String id;
private Questions questions;
public QuestionAggregateClass() {
}
#CommandHandler
public QuestionAggregateClass(CreateQuestionCommands command) {
var newQuestion=command.getQuestions();
newQuestion.setId(command.getId());
var event = QuestionCreatedEvents.builder()
.id(command.getId())
.questions(newQuestion)
.build();
AggregateLifecycle.apply(event);
}
#EventSourcingHandler
public void on(QuestionCreatedEvents event){
this.id=event.getId();
this.questions=event.getQuestions();
}
}
Here i want to make a static list so that when i post data from postman, it will save in that static list and i am able to getData from here also. But i dont know how to make that fucnction while using lambda expression. I dont want to write dummy data manually here, i want to store it from postman sending post request
public class QuestionDataAsList {
public static List<Questions> questions;
public static void save(Questions questions) {
}
}
And want to make implementation of event here, and want to call static list here.
#Component
public class QuestionEventHandlerImp implements QuestionEventHandler{
#Override
public void on(QuestionCreatedEvents event) {
QuestionDataAsList.save(event.getQuestions());
}
My code is exactly the same as the example shown on py4j website:
Implementing Java Interfaces from Python
Except my classes are all in the same src.main.java package
(see below for the code)
Problem:
If I do a gradle fatjar build with ListenerApplication as main, then execute the jar, everything works fine. If I do a gradle fatjar build and instead access the code via a plugin interface, I get the following error:
Py4JError: An error occurred while calling o0.registerListener. Trace:
py4j.Py4JException: Invalid interface name: ExampleListener
at py4j.Protocol.getPythonProxy(Protocol.java:429)
at py4j.Protocol.getObject(Protocol.java:311)
at py4j.commands.AbstractCommand.getArguments(AbstractCommand.java:82)
at py4j.commands.CallCommand.execute(CallCommand.java:77)
at py4j.GatewayConnection.run(GatewayConnection.java:238)
at java.lang.Thread.run(Thread.java:748)
Question: Why does Py4J have problems finding "ExampleListener" when the .jar is run as a plugin and not as an application? I can even add :
public String classtest() throws Exception {
System.out.println("classtest called");
Class<?> py = Class.forName("ExampleListener");
return py.toString();
}
to the ListenerApplication, which will return the correct interface both when run as plugin and as application! The interesting thing is, if I run the program plus plugin from netbeans IDE, everything works fine! Does Netbeans somehow expose the interface, while the application run directly, does not?
Plugin interface
import org.micromanager.MenuPlugin;
import org.micromanager.Studio;
import org.scijava.plugin.Plugin;
import org.scijava.plugin.SciJavaPlugin;
import py4j.GatewayServer;
#Plugin(type = MenuPlugin.class)
public class Py4JPluginInterface implements MenuPlugin, SciJavaPlugin{
private static final String menuName = "Simpletest_gradle";
private static final String tooltipDescription = "py4j gateway";
private static final String version = "0.1";
private static final String copyright = "copyright";
#Override
public String getSubMenu() {
return "Simpletest_gradle";
}
#Override
public void onPluginSelected() {
GatewayServer gatewayServer = new GatewayServer(new ListenerApplication());
gatewayServer.start();
System.out.println("Gateway Started at IP:port = "+gatewayServer.getAddress()+":"+gatewayServer.getPort());
}
#Override
public void setContext(Studio app) {
}
#Override
public String getName() {
return menuName;
}
#Override
public String getHelpText() {
return tooltipDescription;
}
#Override
public String getVersion() {
return version;
}
#Override
public String getCopyright() {
return copyright;
}
}
The interface:
//py4j/examples/ExampleListener.java
package py4j.examples;
public interface ExampleListener {
Object notify(Object source);
}
The application:
package py4j.examples;
import py4j.GatewayServer;
import java.util.ArrayList;
import java.util.List;
public class ListenerApplication {
List<ExampleListener> listeners = new ArrayList<ExampleListener>();
public void registerListener(ExampleListener listener) {
listeners.add(listener);
}
public void notifyAllListeners() {
for (ExampleListener listener: listeners) {
Object returnValue = listener.notify(this);
System.out.println(returnValue);
}
}
#Override
public String toString() {
return "<ListenerApplication> instance";
}
public static void main(String[] args) {
ListenerApplication application = new ListenerApplication();
GatewayServer server = new GatewayServer(application);
server.start(true);
}
}
The python listener
from py4j.java_gateway import JavaGateway, CallbackServerParameters
class PythonListener(object):
def __init__(self, gateway):
self.gateway = gateway
def notify(self, obj):
print("Notified by Java")
print(obj)
gateway.jvm.System.out.println("Hello from python!")
return "A Return Value"
class Java:
implements = ["py4j.examples.ExampleListener"]
if __name__ == "__main__":
gateway = JavaGateway(
callback_server_parameters=CallbackServerParameters())
listener = PythonListener(gateway)
gateway.entry_point.registerListener(listener)
gateway.entry_point.notifyAllListeners()
gateway.shutdown()
For those who are interested, this was a class loader issue, which is apparently common for plugin/OSGI apps.
See the maintainer's response:
https://github.com/bartdag/py4j/issues/339#issuecomment-473655738
I simply added the following to the Java-side ListenerApplication constructor:
RootClassLoadingStrategy rmmClassLoader = new RootClassLoadingStrategy();
ReflectionUtil.setClassLoadingStrategy(rmmClassLoader);
I want use API of BitSkins.com, but they use two-factor codes through Authy. For request on BitSkins I need API_key and code.
By link: https://bitskins.com/api/, maybe wrote about it, but they haven't solution for JAVA.
https://bitskins.com/api/v1/get_account_balance/?api_key=I_KNOW_IT&code=**CODE_IN_PHONE_GENERATE_AUTOMATICALY**
How to receive same code CODE_IN_PHONE_GENERATE_AUTOMATICALY, like I received in my Authy application on my phone?
I was having the same issues as OP. Just Googling stuff for 5 minutes solved that.
I am using this little API here.
My implementation might quite a bit different from you as I am doing this as a part of very big project and my company is funding this.
Spring Implementation
In our application, the process is automated and we are using Spring Framework. I have created a bean which is nothing but a Thread that runs indefinitely and generates the Authy code (same as shown in the mobile phone).
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import com.sarvika.commonslib.util.StringUtil;
import com.j256.totp.TwoFactorAuthUtil;
public class Authy2FactorThreadBean extends Thread implements ApplicationContextAware {
private static final Logger logger = Logger.getLogger(Authy2FactorThreadBean.class);
private String base32Secret;
private String keyId;
private String qrCodeImageUrl;
private String code;
#Override
public void run() {
try {
TwoFactorAuthUtil twoFactorAuthUtil = new TwoFactorAuthUtil();
qrCodeImageUrl = twoFactorAuthUtil.qrImageUrl(keyId, base32Secret);
code = twoFactorAuthUtil.generateCurrentNumber(base32Secret);
while (true) {
code = twoFactorAuthUtil.generateCurrentNumber(base32Secret);
Thread.sleep(1000);
}
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
#Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
if (StringUtil.isEmpty(base32Secret) || StringUtil.isEmpty(keyId)) {
logger.warn("Base32 Secret or Key ID not provided. 2Factor Codes will not be generated!!!!!");
return;
}
logger.info("Starting 2Factor Generation Thread...");
start();
}
public String getBase32Secret() {
return base32Secret;
}
public void setBase32Secret(String base32Secret) {
this.base32Secret = base32Secret;
}
public String getKeyId() {
return keyId;
}
public void setKeyId(String keyId) {
this.keyId = keyId;
}
public String getQrCodeImageUrl() {
return qrCodeImageUrl;
}
public void setQrCodeImageUrl(String qrCodeImageUrl) {
this.qrCodeImageUrl = qrCodeImageUrl;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
Then you create a bean like this:
<bean id="authy2FactorThreadBean" class="Authy2FactorThreadBean">
<!-- twofactor.secret is the Secret shown by the Bitskins when you are authorizing your phone -->
<property name="base32Secret" value="${twofactor.secret}"/>
<!-- twofactor.key is the name of the key which can be displayed by the authenticator program -->
<property name="keyId" value="${twofactor.key}"/>
</bean>
And pass it around wherever you want the generated two-factor code.
Non-Spring Implementation
Please see this little example by the API Author.
I am trying to send a date from flex side to java using BlazeDS
field type in flex
private var _scheduleDate:Date;
I have initialized it with new Date() , and if alert it, correct date and time is displayed as on my system. now when the object is sent to java. the date get changed.
Please note that my flex application and java (JBoss server is running on same machine). If i independently print a date on java side initialized with new Date(), it also display correct date as of the system.
Now conversion part: on flex it was
25/04/2013 12:30 PM (as Alert displayed)
when i print this passed date(at java side), its
25/04/2013 02:30 PM (2 hours difference)
I have read many blogs etc for the solution, they refer it a time zone issue, but i didnt get it, if client and server are both on single system, how could time zone issue causes this problem.
Alert(flex) and println(java) with new Date() display correct date as of the system, so how that timezone issue comes in. only i can think of is, BlazeDS is causing this issue.
Here in this link they have refered some custom marshling for blazeDS but it went above my head
Custom Marshalling from Java to Flex via BlazeDS
Right now i have only one solution for this problem to send date in String as plain text instead of Date object and convert String back to Date object on java side.
Is there any better solution or if there is any issue with my understanding can someone please point out that.
Thanks,
I suggest the following solution.
First, send client timezone offset and store it as a session attribute.
Flex
ro.setClientTimezoneOffset(-new Date().getTimezoneOffset() * 60 * 1000);
Java
public void setClientTimezoneOffset(Long t) {
FlexContext.getFlexSession().setAttribute("clientTimezoneOffset", t);
}
Create our own endpoint class extending flex.messaging.endpoints.AMFEndpoint and point it at channel definition:
services-config.xml
<channel-definition id="my-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
class="com.package.AMFEndpoint"/>
</channel-definition>
AMFEndpoint.java
package com.package;
public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {
#Override
protected String getSerializerClassName() {
return Serializer.class.getName();
}
#Override
protected String getDeserializerClassName() {
return Deserializer.class.getName();
}
}
Extend amf serializer, deserializer, amf input/output:
Serializer.java
package com.package;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.AmfTrace;
import java.io.OutputStream;
public class Serializer extends AmfMessageSerializer {
#Override
public void initialize(SerializationContext context, OutputStream out, AmfTrace trace) {
amfOut = new AMF0Output(context);
amfOut.setOutputStream(out);
amfOut.setAvmPlus(version >= MessageIOConstants.AMF3);
debugTrace = trace;
isDebug = trace != null;
amfOut.setDebugTrace(debugTrace);
}
}
Deserializer.java
package com.package;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageDeserializer;
import flex.messaging.io.amf.AmfTrace;
import java.io.InputStream;
public class Deserializer extends AmfMessageDeserializer {
#Override
public void initialize(SerializationContext context, InputStream in, AmfTrace trace) {
amfIn = new AMF0Input(context);
amfIn.setInputStream(in);
debugTrace = trace;
isDebug = debugTrace != null;
amfIn.setDebugTrace(debugTrace);
}
}
AMF0Input.java
package com.package;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf0Input;
import java.io.IOException;
public class AMF0Input extends Amf0Input {
public AMF0Input(SerializationContext context) {
super(context);
}
#Override
public Object readObject() throws ClassNotFoundException, IOException {
if (avmPlusInput == null) {
avmPlusInput = new AMF3Input(context);
avmPlusInput.setDebugTrace(trace);
avmPlusInput.setInputStream(in);
}
return super.readObject();
}
}
AMF0Output.java
package com.package;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf0Output;
public class AMF0Output extends Amf0Output {
public AMF0Output(SerializationContext context) {
super(context);
}
#Override
protected void createAMF3Output()
{
avmPlusOutput = new AMF3Output(context);
avmPlusOutput.setOutputStream(out);
avmPlusOutput.setDebugTrace(trace);
}
}
And finally you extend amf 3 input/output classes, where date is serialized and deserialized. You apply offset difference.
AMF3Input.java
package com.package;
import flex.messaging.FlexContext;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import java.io.IOException;
import java.util.Date;
public class AMF3Input extends Amf3Input {
#Override
protected Date readDate() throws IOException {
Date d = super.readDate();
if (d != null) {
Long clientOffset = (Long) FlexContext.getFlexSession().getAttribute("clientTimezoneOffset");
Long serverOffset = (Long) (-d.getTimezoneOffset() * 60L * 1000);
d.setTime(d.getTime() - (serverOffset - clientOffset));
}
return d;
}
public AMF3Input(SerializationContext context) {
super(context);
}
}
AMF3Output.java
package com.package;
import flex.messaging.FlexContext;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Output;
import java.io.IOException;
import java.util.Date;
public class AMF3Output extends Amf3Output {
public AMF3Output(SerializationContext context) {
super(context);
}
#Override
protected void writeAMFDate(Date d) throws IOException {
if (d != null) {
Long clientOffset = (Long) FlexContext.getFlexSession().getAttribute("clientTimezoneOffset");
Long serverOffset = (Long) (-d.getTimezoneOffset() * 60L * 1000);
d.setTime(d.getTime() + (serverOffset - clientOffset));
}
super.writeAMFDate(d);
}
}
Now all dates, passed between Flex front-end and BlazeDS back-end will be automatically converted. Note, that you actually change the date.
Assume server time zone is GMT+6, and client is in GMT+2 timezome.
You're retrieving date from database. The date on java is 01.01.2013 10.00.00 GMT+6, normally flex would get 01.01.2013 06.00.00 GMT+2. It's the same date, but String equivalent differs. In our case flex will get 01.01.2013 10.00.00 GMT+2. We changed the date. But string equivalent is the same.
In addition create another class for compatibility with previous versions of Java:
package br.com.ultreia.flex;
import java.io.OutputStream;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfTrace;
public class Java15AmfMessageSerializer extends flex.messaging.io.amf.Java15AmfMessageSerializer{
#Override
public void initialize(SerializationContext context, OutputStream out, AmfTrace trace) {
amfOut = new AMF0Output(context);
amfOut.setOutputStream(out);
amfOut.setAvmPlus(version >= MessageIOConstants.AMF3);
debugTrace = trace;
isDebug = trace != null;
amfOut.setDebugTrace(debugTrace);
}
}
And I changed the class AMFEndpoint.java
public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {
public AMFEndpoint(){
super();
}
#Override
protected String getSerializerClassName() {
return Serializer.class.getName();
}
#Override
protected String getSerializerJava15ClassName() {
return Java15AmfMessageSerializer.class.getName();
}
#Override
protected String getDeserializerClassName() {
return Deserializer.class.getName();
}
}
In Jersey, how can we 'replace' the status string associated with a known status code?
e.g.
return Response.status(401).build();
generates a HTTP response that contains:
HTTP/1.1 401 Unauthorized
I (not me, but the client application) would like to see the response as:
HTTP/1.1 401 Authorization Required
I tried the following approaches but in vain:
1) This just adds the String in the body of the HTTP response
return Response.status(401).entity("Authorization Required").build();
2) Same result with this too:
ResponseBuilder rb = Response.status(401);
rb = rb.tag("Authorization Required");
return rb.build();
Appreciate your help!
-spd
To do this in Jersey you have the concept of WebApplicationException class. One method is to simply extend this class and all one of the methods to set the error text that is returned. In your case this would be:
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;
public class UnauthorizedException extends WebApplicationException {
/**
* Create a HTTP 401 (Unauthorized) exception.
*/
public UnauthorizedException() {
super(Response.status(Status.UNAUTHORIZED).build());
}
/**
* Create a HTTP 404 (Not Found) exception.
* #param message the String that is the entity of the 404 response.
*/
public UnauthorizedException(String message) {
super(Response.status(Status.UNAUTHORIZED).entity(message).type("text/plain").build());
}
}
Now in your code that implements the rest service you would simply throw a new exception of this type, passing in the text value in the constructor e.g.
throw new UnauthorizedException("Authorization Required");
That can create a class like this for each of your web exceptions and throw in a similar fashion.
This is also explained in the Jersey user guide - although the code is actually slightly incorrect:
https://jersey.github.io/nonav/documentation/latest/user-guide.html/#d4e435
I'm not sure JSR 339: JAX-RS 2.0: The Java API for RESTful Web Services already covered this or not.
You might have to extend the Response.StatusType for this.
public abstract class AbstractStatusType implements StatusType {
public AbstractStatusType(final Family family, final int statusCode,
final String reasonPhrase) {
super();
this.family = family;
this.statusCode = statusCode;
this.reasonPhrase = reasonPhrase;
}
protected AbstractStatusType(final Status status,
final String reasonPhrase) {
this(status.getFamily(), status.getStatusCode(), reasonPhrase);
}
#Override
public Family getFamily() { return family; }
#Override
public String getReasonPhrase() { return reasonPhrase; }
#Override
public int getStatusCode() { return statusCode; }
public ResponseBuilder responseBuilder() { return Response.status(this); }
public Response build() { return responseBuilder().build(); }
public WebApplicationException except() {
return new WebApplicationException(build());
}
private final Family family;
private final int statusCode;
private final String reasonPhrase;
}
And here are some extended statust types.
public class BadRequest400 extends AbstractStatusType {
public BadRequest400(final String reasonPhrase) {
super(Status.BAD_REQUEST, reasonPhrase);
}
}
public class NotFound404 extends AbstractStatusType {
public NotFound404(final String reasonPhrase) {
super(Status.NOT_FOUND, reasonPhrase);
}
}
This is how I do.
#POST
public Response create(final MyEntity entity) {
throw new BadRequest400("bad ass").except();
}
#GET
public MyEntity read(#QueryParam("id") final long id) {
throw new NotFound404("ass ignorant").except();
}
// Disclaimer
// I'm not a native English speaker.
// I don't know what 'bad ass' or 'ass ignorant' means.