I'm going mad with an error non error on my web-app Flex 3.6 based (using BlazeDS). I try to describe my issue: I have a java class:
public class User {...}
and the binding one in .as:
[Bindable]
[RemoteClass(alias="it.dto.User")]
public class User {...}
I also have a DataManager.as to do the Async call like this:
public function getUser():void {
var token:AsyncToken = _service.getUser();
token.addResponder(new AsyncResponder(userOnResult,userOnFault));
}
private function userOnFault(event:FaultEvent,token:Object):void {
var _fail:String = "Error";
}
private function socOnResult(event:ResultEvent,token:Object):void {
_resUser = event.result as ArrayCollection;
dispatchEvent(new MyEvent("USER_EVENT",_resUser));
}
Now I implemented the following code in two different .as file (different package), which refers to two different .mxml:
var data:DataManager = new DataManager;
....
data.addEventListener("USER_EVENT",userResult);
....
data.getUser();
....
private function userResult(dataEvent:MyEvent):void {
var user:ArrayCollection = new ArrayCollection;
user = dataEvent.result as ArrayCollection;
for (var i:int = 0;i<user.length; i++) {
var u:User = new User;
u = (User)(user.getItemAt(i));
}
_dm.removeEventListener("USER_EVENT",userResult);
}
The drama is that in the first .as it works perfectly, and in the second .as give me a Error of coercion failed. In the second file seems how it can't recognize the User class.
Do you have any idea?? I'm going mad!!
Thank you
#Stacktrace error:
TypeError: Error #1034: Type Coercion failed: cannot convert appcode.dto::SocietaDTO#b4dbfc1 to appcode.dto.SocietaDTO.
at modules::ReportIspezioni/onSocResult()[D:\workspace\maga\aga\flex_src\modules\ReportIspezioni_src.as:80]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at appcode.dao::DataManager/socOnResult()[D:\workspace\maga\aga\flex_src\appcode\dao\DataManager.as:180]
at mx.rpc::AsyncResponder/result()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AsyncResponder.as:82]
at mx.rpc::AsyncToken/http://www.adobe.com/2006/flex/mx/internal::applyResult()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AsyncToken.as:199]
at mx.rpc.events::ResultEvent/http://www.adobe.com/2006/flex/mx/internal::callTokenResponders()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\events\ResultEvent.as:172]
at mx.rpc::AbstractOperation/http://www.adobe.com/2006/flex/mx/internal::dispatchRpcEvent()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AbstractOperation.as:199]
at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::resultHandler()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AbstractInvoker.as:263]
at mx.rpc::Responder/result()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\Responder.as:46]
at mx.rpc::AsyncRequest/acknowledge()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AsyncRequest.as:74]
at NetConnectionMessageResponder/resultHandler()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\messaging\channels\NetConnectionChannel.as:524]
at mx.messaging::MessageResponder/result()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\messaging\MessageResponder.as:199]
Obviusly the User class written above is just for example, to understand the code logic. The real class is a DTO calls SocietaDTO.
N.B: The code works perfectly in another module of my project.. I don't understand why here it doesn't work.
Thanks a lot
I never save browser cache when developing.. Anyway I solve the Issue by adding this:
registerClassAlias("it.mec.dto.SocietaDTO", SocietaDTO);
In the class were exception launch.
Thanks anyway
Related
I need to unit test a method, and I would like mock the behavior so that I can test the necessary part of the code in the method.
For this I would like access the object returned by a private method inside the method I am trying to test. I created a sample code to give a basic idea of what I am trying to achieve.
Main.class
Class Main {
public String getUserName(String userId) {
User user = null;
user = getUser(userId);
if(user.getName().equals("Stack")) {
throw new CustomException("StackOverflow");
}
return user.getName();
}
private User getUser(String userId) {
// find the user details in database
String name = ""; // Get from db
String address = ""; // Get from db
return new User(name, address);
}
}
Test Class
#Test (expected = CustomException.class)
public void getUserName_UserId_ThrowsException() {
Main main = new Main();
// I need to access the user object returned by getUser(userId)
// and spy it, so that when user.getName() is called it returns Stack
main.getUserName("124");
}
There are only two ways to access private:
using reflection
extend the scope
maybe waiting for Java 9 to use new scope mechanisms?
I would change the scope modifier from private to package scope. Using reflection is not stable for refactoring. It doesn't matter if you use helpers like PowerMock. They only reduce the boiler-plate code around reflection.
But the most important point is you should NOT test too deep in whitbox tests. This can make the test setup explode. Try to slice your code into smaller pieces.
The only information the method "getUserName" needs from the User-object is the name. It will validate the name and either throw an exception or return it. So it should not be necessary to introduce a User-object in the test.
So my suggestion is you should extract the code retreiving the name from the User-object into a separate method and make this method package scope. Now there is no need to mock a User-Object just the Main-Object. But the method has its minimal information available to work properly.
class Main {
public String getUserName(String userId) {
String username = getUserNameFromInternal(userId);
if (userName.equals("Stack")) {
throw new CustomException("StackOverflow");
}
return user.getName();
}
String getUserNameFromInternal(String userId) {
User user = getUser(userId);
return user.getName();
}
...
}
The test:
#Test (expected = CustomException.class)
public void getUserName_UserId_ThrowsException() {
Main main = Mockito.mock(new Main());
Mockito.when(main.getUserNameInternal("124")).thenReturn("Stack");
main.getUserName("124");
}
Your problem that call to new within your private method.
And the answer is not to turn to PowerMock; or to change the visibility of that method.
The reasonable answer is to "extract" that dependency on "something that gives me a User object" into its own class; and provide an instance of that class to your "Main" class. Because then you are able to simply mock that "factory" object; and have it do whatever you want it to do.
Meaning: your current code is simply hard-to-test. Instead of working around the problems that are caused by this, you invest time in learning how to write easy-to-test code; for example by watching these videos as a starting point.
Given your latest comment: when you are dealing with legacy code, then you are really looking towards using PowerMockito. The key part to understand: you don't "mock" that private method; you rather look into mocking the call to new User() instead; as outlined here.
You can use a PowerMock's mockPrivate but I don't recommend it.
If you has such a problem it usually mean that your design is bad.
Why not making the method protected?
OK, so I have an interesting problem. I am using java/maven/spring-boot/cassandra... and I am trying to create a dynamic instantiation of the Mapper setup they use.
I.E.
//Users.java
import com.datastax.driver.mapping.annotations.Table;
#Table(keyspace="mykeyspace", name="users")
public class Users {
#PartitionKey
public UUID id;
//...
}
Now, in order to use this I would have to explicitly say ...
Users user = (DB).mapper(Users.class);
obviously replacing (DB) with my db class.
Which is a great model, but I am running into the problem of code repetition. My Cassandra database has 2 keyspaces, both keyspaces have the exact same tables with the exact same columns in the tables, (this is not my choice, this is an absolute must have according to my company). So when I need to access one or the other based on a form submission it becomes a mess of duplicated code, example:
//myWebController.java
import ...;
#RestController
public class MyRestController {
#RequestMapping(value="/orders", method=RequestMethod.POST)
public string getOrders(...) {
if(Objects.equals(client, "first_client_name") {
//do all the things to get first keyspace objects like....
FirstClientUsers users = (db).Mapper(FirstClientUsers.class);
//...
} else if(Objects.equals(client, "second_client_name") {
SecondClientUsers users = (db).Mapper(SecondClientUsers.class);
//....
}
return "";
}
I have been trying to use methods like...
Class cls = Class.forName(STRING_INPUT_VARIABLE_HERE);
and that works ok for base classes but when trying to use the Accessor stuff it no longer works because Accessors have to be interfaces, so when you do Class cls, it is no longer an interface.
I am trying to find any other solution on how to dynamically have this work and not have to have duplicate code for every possible client. Each client will have it's own namespace in Cassandra, with the exact same tables as all other ones.
I cannot change the database model, this is a must according to the company.
With PHP this is extremely simple since it doesn't care about typecasting as much, I can easily do...
function getData($name) {
$className = $name . 'Accessor';
$class = new $className();
}
and poof I have a dynamic class, but the problem I am running into is the Type specification where I have to explicitly say...
FirstClientUsers users = new FirstClientUsers();
//or even
FirstClientUsers users = Class.forName("FirstClientUsers");
I hope this is making sense, I can't imagine that I am the first person to have this problem, but I can't find any solutions online. So I am really hoping that someone knows how I can get this accomplished without duplicating the exact same logic for every single keyspace we have. It makes the code not maintainable and unnecessarily long.
Thank you in advance for any help you can offer.
Do not specify the keyspace in your model classes, and instead, use the so-called "session per keyspace" pattern.
Your model class would look like this (note that the keyspace is left undefined):
#Table(name = "users")
public class Users {
#PartitionKey
public UUID id;
//...
}
Your initialization code would have something like this:
Map<String, Mapper<Users>> mappers = new ConcurrentHashMap<String, Mapper<Users>>();
Cluster cluster = ...;
Session firstClientSession = cluster.connect("keyspace_first_client");
Session secondClientSession = cluster.connect("keyspace_second_client");
MappingManager firstClientManager = new MappingManager(firstClientSession);
MappingManager secondClientManager = new MappingManager(secondClientSession);
mappers.put("first_client", firstClientManager.mapper(Users.class));
mappers.put("second_client", secondClientManager.mapper(Users.class));
// etc. for all clients
You would then store the mappers object and make it available through dependency injection to other components in your application.
Finally, your REST service would look like this:
import ...
#RestController
public class MyRestController {
#javax.inject.Inject
private Map<String, Mapper<Users>> mappers;
#RequestMapping(value = "/orders", method = RequestMethod.POST)
public string getOrders(...) {
Mapper<Users> usersMapper = getUsersMapperForClient(client);
// process the request with the right client's mapper
}
private Mapper<Users> getUsersMapperForClient(String client) {
if (mappers.containsKey(client))
return mappers.get(client);
throw new RuntimeException("Unknown client: " + client);
}
}
Note how the mappers object is injected.
Small nit: I would name your class User in the singular instead of Users (in the plural).
I have following controller:
public static Result overview() {
class Earning {
public int ammount;
public String description;
}
Earning[] earnings = new Earning[5];
earnings[0].ammount = 5;
return ok(overview.render(earnings));
}
I didn't created corresponding object in array as a result in Java I should get: java.lang.NullPointerException
But instead of showing this error Play framework crashes.
Any ideas how not to crash the framework and see the error in first place?
Add:
earnings[0] = new Earning();
before:
earnings[0].ammount = 5;
This way, earnings[0] will hold an Earning object and you would be able to access its ammount field.
Don't declare the Earning class inside the overview method.
It's creating a visibility issue because this class should only be accessible in the method body, but your "leaking" it by passing it to a view.
I have a method where I want to factor out some code into its own method
This is what I have:
public class TD0301AssignmentForm extends Form {
public TD0301AssignmentForm(TD0301AssignmentDAO dao, STKUser authenticatedUser) {
this.dao = dao;
this.authenticatedUser = authenticatedUser;
}
public Object insert(HttpServletRequest request) {
TD0301Assignment tdas = new TD0301Assignment();
TD0301Assignment tdas_orig = null;
Date dateNow = new Date();
try {
// Get the inuput from HTML form
tdas.setCalc_num(FormUtil.getFieldValue(request, FIELD_CALC_NUM));
processDate(request, tdas);
tdas.setCalc_dept(FormUtil.getFieldValue(request, FIELD_CALC_DEPT));
tdas.setYear_oi(Integer.toString(DateUtil.getIntYear(dateNow)));
processCalcSafetyRequirements(request, tdas);
...etc...
if (isSucces()) {
// Instantiate a base work flow instance!
WorkflowInstance wfi = new WorkflowInstance();
WorkflowInstanceDAO wfiDAO = new WorkflowInstanceDAO();
wfi.setWorkflow_class_id(tdas.getCalc_level());
wfi.setStarted_by(authenticatedUser.getBadge());
wfi.setStatus("0");
wfi.setLast_date(dateNow);
// Insert the WorkFlowInstance into the database, db sets returned sequence number into the wfi object.
wfiDAO.insert(wfi, authenticatedUser);
// Insert the TD0301Assignment into the db
tdas.setWorkflow_instance_id(wfi.getWorkflow_instance_id());
}
I'd like to remove the WorkflowInstance code out into its own method (still in this Class) like this:
if (isSucces()) {
insertWorkFlowInstance(request, tdas);
tdas.setWorkflow_instance_id(wfi.getWorkflow_instance_id());
but wfi is now marked by Eclipse as not available. Should I do something like this to fix the error so that I can still get the wfi.getWorkflow_instance_id() in the isSuccess block above? I know it removes the error, but I am trying to apply best practices.
public class TD0301AssignmentForm extends Form {
private WorkflowInstance wfi = new WorkflowInstance();
private WorkflowInstanceDAO wfiDAO = new WorkflowInstanceDAO();
Instance variables ("properties" or "fields") are not necessarily the way to go if they're not used throughout the entire class.
Variables should have the smallest scope possible--this makes code easier to reason about.
With some noise elided, and also guessing, it seems like the WorkflowInstance and WorkflowInstanceDao could be localized (names changed to match Java conventions):
public class TD0301AssignmentForm extends Form {
public Object insert(HttpServletRequest request) {
TD0301Assignment tdas = new TD0301Assignment();
try {
tdas.setCalcNum(FormUtil.getFieldValue(request, FIELD_CALC_NUM));
processDate(request, tdas);
tdas.setCalcDept(FormUtil.getFieldValue(request, FIELD_CALC_DEPT));
tdas.setYearOi(Integer.toString(DateUtil.getIntYear(dateNow)));
processCalcSafetyRequirements(request, tdas);
if (isSuccess()) {
WorkflowInstance wf = buildWorkflow(tdas);
tdas.setWorkflowInstanceId(wf.getId());
}
}
}
private buildWorkflow(TD0301Assignment tdas) {
WorkflowInstance wfi = new WorkflowInstance();
wfi.setWorkflowClassId(tdas.getCalcLevel());
wfi.setStartedBy(authenticatedUser.getBadge());
wfi.setStatus("0");
wfi.setLastDate(new Date());
WorkflowInstanceDao wfiDao = new WorkflowInstanceDao();
wfiDao.insert(wfi, authenticatedUser);
}
}
Whether or not this is appropriate depends on how/if the WorkflowInstance is used in the rest of the method snippet you show. The DAO is almost certainly able to be localized.
As methods become smaller and easier to think about, they become more testable.
For example, buildWorkflow is almost easy to test, except that the DAO is instantiated "manually". This means that testing the method will either (a) depend on having a working DAO layer, or (b) it must be mocked by a framework that can mock static utility methods (several can).
Without seeing all your code it's not easy to see exactlywhat you are trying to achieve. The reason eclipse is complaining is because it no longer has a wfi instance to play with because you've moved its local instance into your method, but creating another wfi instance is not likely to be your answer.
To get this working change the wfi to be class local and either use it's id directly or return wfi.getWorkflow_instance_id() from insertWorkFlowInstance() and then pass that value into tdas.setWorkflow_instance_id()
I have a working Flex/Java application, but if I log out of the channelSet and log back in, in the debug console I am seeing numerous instances of this error:
ReferenceError: Error #1056: Cannot create property smallMessage on mx.messaging.messages.AcknowledgeMessage.
The error itself doesn't seem to interfere with app.
The AcknowledgeMessage class is not my class -- and I don't know why the Java side and Flex side don't match up with regard to properties on their internal classes.
Any help is appreciated.
Versions:
Flex 4.1.0.16076
BlazeDS 4.0.0.14931
Spring-Flex 1.5.0.RELEASE
We are having exactly the same problem in our application. I've managed to hide the error using the following ugly hack.
First, create a class like so:
public class FixedAcknowledgeMessage extends AcknowledgeMessage {
private var _smallMessage : *;
public function FixedAcknowledgeMessage() { }
public function get smallMessage() : * {
return _smallMessage;
}
public function set smallMessage(value : *) : void {
_smallMessage = value;
}
}
And then, in your startup code, replace AcknowledgeMessage with your fixed one:
registerClassAlias("flex.messaging.messages.AcknowledgeMessage", FixedAcknowledgeMessage);
We also do the same hack for the classes ErrorMessage and AsyncMessage, which seem to suffer from the same problem. I have no idea if this hack may have some negative side effects, and I would love to find a more proper fix for it.
don't use same name as primary key what you used in the table name...
Use different name .....
for example......
VO object...
public class ColumnNameVO
{
public var ifId:int;
public var formatId:int;
public var position:int;
public var name:String;
public function ColumnNameVO() { }
}
Table pojo classs:
public class ColumnNameVO
{
public var Id:int;
public var formatId:int;
public var position:int;
public var name:String;
}