I am using gwt with gwt-platform and making a server call with the dispatch async. The issue I am running into is that the Action that I am using is not being marked as serializable or being added to the *.gwt.rpc file. When my code run I get a
com.google.gwt.user.client.rpc.SerializationException
at com.google.gwt.user.client.rpc.impl.SerializerBase.getTypeHandler(SerializerBase.java:153)
at com.google.gwt.user.client.rpc.impl.SerializerBase.serialize(SerializerBase.java:125)
at com.google.gwt.user.client.rpc.impl.ClientSerializationStreamWriter.serialize(ClientSerializationStreamWriter.java:183)
at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:126)
at com.gwtplatform.dispatch.shared.DispatchService_Proxy.execute(DispatchService_Proxy.java:33)
at com.gwtplatform.dispatch.client.DefaultDispatchAsync.serviceExecute(DefaultDispatchAsync.java:126)
at com.gwtplatform.dispatch.client.DefaultDispatchAsync.execute(DefaultDispatchAsync.java:...
The Action:
public class FindCallsWithFilterAction extends UnsecuredActionImpl<FindCallsWithFilterResult> {
public FindCallsWithFilterAction() {
}
public Date getAfter() {
return after;
}
public Date getBefore() {
return before;
}
public Long getReferenceNumber() {
return referenceNumber;
}
public String getUser() {
return user;
}
public void setAfter(Date after) {
this.after = after;
}
public void setBefore(Date before) {
this.before = before;
}
public void setReferenceNumber(Long referenceNumber) {
this.referenceNumber = referenceNumber;
}
public void setUser(String user) {
this.user = user;
}
public boolean hasAfter(){
return null != after;
}
public boolean hasBefore(){
return null != before;
}
public boolean hasReferenceNumber(){
return null != referenceNumber;
}
public boolean hasUser(){
return null != user;
}
private Date after = null;
private Date before = null;
private Long referenceNumber = null;
private String user = null;
}
The Action has result and a Handler and the handler is bound in my server module. When I debug the code and look at the Serialization map that gwt generates this action and its result aren't there event though this implements the isSerializable interface (in the super class, it still doesn't work if I use Serializable or isSerializable at this level either). Also when I look into my *.gwt.rpc file the class is not in there either. I'm just stuck and was hoping some one would know what to do or what was wrong.
Update: I don't know if it is relevant but I am using spring on the server.
I found my problem. I had forgotten a no-arg constructor in my Result object, also I was using a Builder to create my action and for some reason that was causing the serialization issue once I stopped using the Builder pattern everything ran smoothly.
Related
I have the Feature class as follows:
public class Feature {
private FeatureType featureType;
private Integer featureNumber;
#JsonProperty("isActive")
private boolean isActive;
#JsonProperty("isAutomatedFeature")
private boolean isAutomatedFeature;
private Feature() {
}
public FeatureType getFeatureType() {
return featureType;
}
public Integer getFeatureNumber() {
return featureNumber;
}
#JsonProperty("isActive")
public boolean isActive() {
return isActive;
}
#JsonProperty("isAutomatedFeature")
public boolean isAutomatedFeature() {
return isAutomatedFeature;
}
public static class Builder {
Feature feature=null;
public Builder() {
feature=new Feature();
}
public Builder setFeatureType(FeatureType featureType) {
feature.featureType=featureType;
return this;
}
public Builder setFeatureNumber(Integer featureNumber) {
feature.featureNumber=featureNumber;
return this;
}
#JsonProperty("isActive")
public Builder setIsActive(boolean isActive) {
feature.isActive=isActive;
return this;
}
#JsonProperty("isAutomatedFeature")
public Builder setIsCarryForwardAllowed(boolean isAutomatedFeature) {
feature.isAutomatedFeature=isAutomatedFeature;
return this;
}
public Feature build() {
return feature;
}
}
Now to create a feature we have an api called
api/v1/feature---POST and its payload will look like below:
"feature":{
"featureType":"XYZ",
"featureType":"40",
"isActive" :true,
"isAutomatedFeature" :true
}
But we can't call this api directly to create a feature so we use RestAssured RequestSpecificationImpl to hit the above API.
It will be something like this
public Response create(Feature feature) {
return post("api/v1/feature",feature);
}
Internally it creates the payload/body for the url and hit the api.So to hit the above method create we need the feature object which I created using builder.
Feature feature=new Feature.Builder().setFeatureType("XYZ").setFeatureNumber(40).setIsActive(true).setIsCarryForwardAllowed(true).build();
I expected the payload to be like above mentioned payload.
But the generated payload is something like this:
"feature":{
"featureType":"XYZ",
"featureType":"40",
"Active" :true,
"AutomatedFeature" :true
}
i.e it removes "is" from "isActive" and "isAutomatedFeature" and make them "Active" and "AutomatedFeature" respectively even when I am using #JsonProperty,so the api fails.
Can anyone guide me what I am doing wrong or how it can be resolved.
Thanks in advance.
It should be pretty easy but obviously I am lacking of basic knowlege.
I have a service which is ment to create ticket in BugTracking systems.
Creating plugins is pretty stright forward. there is an interface
public interface BugTracker {
boolean createAndSendIssue(Issue issue);
boolean updateAndSendIssue(Issue issue);
boolean closeIssue(Issue issue);
}
and API client for JIRA:
#Component
public class JiraClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
}
API CLient for Bugzilla:
#Component
public class BugzillaClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
}
Problem occurs on the Service which is handling MVC. Piece of it looks like:
#Service
public class BugTrackerService {
private final BugzillaClient bugzillaClient;
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
#Autowired
BugTrackerService(BugzillaClient bugzillaClient, JiraClient jiraClient) {
this.bugzillaClient = bugzillaClient;
this.jiraClient = jiraClient;
}
boolean processIssueTicketRequest(Issue issue){
if ( issue.getBugTrackerType().bugTrackingSystemType.name.equals(JIRA_TYPE)) {
return jiraClient.createAndSendIssue(issue);
} else if (issue.getBugTrackerType().bugTrackingSystemType.name.equals(BUGZILLA_TYPE)){
return bugzillaClient.createAndSendIssue(issue);
} else {
return false;
}
}
}
is it somehow possible to create method BugTrackerService.processIssueTicketRequest without all clients autowired? At this moment it is not so much of a problem but after integrating with more and more systems this service will become complex.
Depending on how reusable you want implementations to be, I'd probably put the logic of checking whether the given issue is of matching typing into the interface, eg
boolean canWorkWithGivenIssue(Issue issue);
With that in place then you don't need to know actual types of trackers you dispatch on, and merely aggregate them into the list. Spring will do that for you if you annotate a collection with #Autowired, in which cases it will provide you all the beans with matching type. Your service then could look like this
#Autowired List<BugTracker> trackers; //autowired on field for brevity
boolean processIssueTicketRequest(Issue issue){
for (BugTracker t : trackers)
if (t.canWorkWithGivenIssue(issue))
return t.createAndSendIssue(issue);
return false;
}
Turn the type into an enum and let the BugTracker decide if it can handle it. Then inject a collection of all BugTracker instances, iterate over them and if it supports the type call the appropriate method.
public enum SystemType { JIRA, BUGZILLA }
Then add a method, for instance supports(Issue issue), to your BugTracker.
boolean supports(Issue issue);
In the implementations check if it can be handled, for instance in the JiraClient do something like this.
public boolean supports(Issue issue) {
return JIRA == issue.getBugTrackerType();
}
Then in your BugTrackerService get a list of all BugTracker instances, iterate and call the appropriate one.
#Service
public class BugTrackerService {
private final List<BugTracker> bugTrackers;
BugTrackerService(List<BugTracker> bugTrackers) {
this.bugTrackers=bugTrackers;
}
boolean processIssueTicketRequest(Issue issue){
for (BugTracker bugTracker : this.bugTrackers) {
if (bugTracker.supports(issue) ) {
bugTracker.createAndSendIssue(issue);
return true;
}
}
return false;
}
}
Now you are as flexible as you want to be and can support as many as you want.
You can pass on the responsibility of finding out the correct implementation of BugTracker to a BugTrackerFactory.
#Component
class BugTrackerFactory {
#Autowired
private final BugzillaClient bugzillaClient;
#Autowired
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
public BugTracker getBugTracker(String type) {
if (JIRA_TYPE.equals(type)) {
return jiraClient;
} else if (BUGZILLA_TYPE.equals(type)) {
return bugzillaClient;
} else {
// throw some exception
}
}
}
BugTrackerService :
#Service
public class BugTrackerService {
private final BugTrackerFactory bugTrackerFactory;
#Autowired
BugTrackerService(BugTrackerFactory bugTrackerFactory) {
this.bugTrackerFactory = bugTrackerFactory;
}
boolean processIssueTicketRequest(Issue issue){
return bugTrackerFactory.getBugTracker(issue.getBugTrackerType().bugTrackingSystemType.name).createAndSendIssue(issue);
}
}
again a small problem by understanding "how tapestry works".
I've got a Tapestry component (in this case a value encoder):
public class EditionEncoder implements ValueEncoder<Edition>, ValueEncoderFactory<Edition> {
#Inject
private IEditionManager editionDao;
public EditionEncoder(IEditionManager editionDao) {
this.editionManager = editionDao;
}
#Override
public String toClient(Edition value) {
if(value == null) {
return "";
}
return value.getName();
}
#Override
public Edition toValue(String clientValue) {
if(clientValue.equals("")) {
return null;
}
return editionManager.getEditionByName(clientValue);
}
#Override
public ValueEncoder<Edition> create(Class<Edition> type) {
return this;
}
}
Injecting the the Manager is not working, because the Encoder is created within a page like that:
public void create() {
editionEncoder = new EditionEncoder();
}
casued by this, i'm forced to use this ugly solution:
#Inject
private IEditionManager editionmanager;
editionEncoder = new EditionEncoder(editionManager);
Is there a better way to inject components during runtime or is there a better solution in general for it?
Thanks for your help in advance,
As soon as you use "new" then tapestry-ioc is not involved in object creation and can't inject. You should inject everything and never use "new" for singleton services. This is true for all ioc containers, not just tapestry-ioc.
Also if you put #Inject on a field then you don't also need a constructor to set it. Do one or the other, never both.
You should do something like this:
public class MyAppModule {
public void bind(ServiceBinder binder) {
binder.bind(EditionEncoder.class);
}
}
Then in your page/component/service
#Inject EditionEncoder editionEncoder;
If you wanted to put your own instantiated objects in there you can do
public class MyServiceModule {
public void bind(ServiceBinder binder) {
binder.bind(Service1.class, Service1Impl.class);
binder.bind(Service2.class, Service2Impl.class);
}
public SomeService buildSomeService(Service1 service1, Service2 service2, #AutoBuild Service3Impl service3) {
Date someDate = new Date();
return new SomeServiceImpl(service1, service2, service3, someDate);
}
}
Hi after countless hours, I figured out what I really what my problem is but still cannot find an answer.
#Override
public void onStampResult(StampResult result) {
}
onStampResult returns a Class StampResult with the follwowing parameters:
public class StampResult implements Serializable {
public SnowShoeError error;
public SnowShoeStamp stamp;
public boolean secure;
public String receipt;
public Date created;
}
SnowShoeStamp Class is:
public class SnowShoeStamp implements Serializable {
public String serial;
}
And SnowShoeError Class is:
public class SnowShoeError implements Serializable {
public int code;
public String message;
}
In onStampResult I can write down logic depending on the output of result.
On Success ´stamp´ gets initialized and ´error´ does not exist.
On Error, stamp does not exist and error gets initialized.
The result gets parsed to from JSON to the Class in the following way:
try {
stampResult = gson.fromJson(result, StampResult.class);
} catch (JsonSyntaxException jsonException) {
stampResult = new StampResult();
stampResult.error = new SnowShoeError();
stampResult.error.message = result;
}
mOnStampListener.onStampResult(stampResult);
mStampBeingChecked = false;
}
How do I test if either error or stamp exists without getting a NullPointerExeption?
Unless I misunderstood your question, you simply need to check for null.
In order to handle the different cases, you could do the following:
#Override
public void onStampResult(StampResult result) {
if (result.error == null){
SnowShoeStamp stamp = result.stamp;
// Process stamp
} else {
SnowShoeError error = stampResult.error;
// Process error
}
}
I have been attempting recently to write a web service that returns a custom object. This object is very simple:
public class AppInfo {
private int AppID;
private String Appname;
private String AppDesc;
private String AppPriv;
public int GetAppID()
{ return this.AppID;}
public void SetAppID(int AppID)
{ this.AppID = AppID;}
public String GetAppName()
{ return this.Appname;}
public void SetAppName(String AppName)
{ this.Appname = AppName;}
public String GetAppDesc()
{ return this.AppDesc;}
public void SetAppDesc(String AppDesc)
{ this.AppDesc = AppDesc;}
public String GetAppPriv()
{ return this.AppPriv;}
public void SetAppPriv(String AppPriv)
{ this.AppPriv = AppPriv; }
public AppInfo()
{}
}
However for whatever reason when NetBeans generates the WSDL and XSD the AppInfo always returns with:
<xs:complexType name="appInfo">
<xs:sequence/>
</xs:complexType>
Searching for any information on returning custom classes seems to lead me back to a rehash of either the calculator or the image web service, neither of which are useful to me. Is it not possible to return a custom object with JAX-WS?
Most probably because you are not using the JavaBean standard for getters/setters? Try changing your getters/setters to
public String getAppPriv()
{ return this.AppPriv;}
public void setAppPriv(String AppPriv)
{ this.AppPriv = AppPriv; }