Unable to find ancestors using recursion - java

I am having trouble getting the "grandparent" of a child.
//main class
User finalAlternate = new User();
for(User user: userList) {
if(user.getAlternateContactId() != null) {
finalAlternate = checkAlternate(user);
approverMap.put(finalAlternate.getId(), user.getId());
}
}
//helper method
public User checkAlternate(User user) { //returns the alternate
User alternateUser = new User();
if(user.getAlternateContactId() != null) {
alternateUser = userMQService.getUser(user.getAlternateContactId(), new UserCollection[]{UserCollection.ROLES, UserCollection.GROUPS});
} else {
return user;
}
return checkAlternate(alternateUser);
}
I have a collection of Users that look something like:
User A -> User B -> User C
All these Users are related with each other due to their alternate contact Id. So User A's alternateContactId is the Id of User B and User B's alternateContacId is the ID of User C. When I run my method my map's result looks something like this:
User C -> User B
So, how would I fix my method so that the map looks like this:
User C -> User A
Basically how can I fix my method so I can get the first ancestor of any child?
Thanks for all the help!

The problem is that you are overwriting previous entries in the Child/GrandParent map. For example.
User finalAlternate = new User();
for(User user: userList) {
if(user.getAlternateContactId() != null) {
// Assuming the users are in the following order in the list [A, B, C]
// In the first iteration you pass A
finalAlternate = checkAlternate(user);
// checkAlternate(A) will traverse A->B->C until it finds C, so when
// this method returns, finalAlternate should be equal to C.
// All good! that is what we wanted
// After the first iteration we have approveMap.put(C, A);
approverMap.put(finalAlternate.getId(), user.getId());
}
}
In the second iteration
for(User user: userList) {
if(user.getAlternateContactId() != null) {
// In the second iteration you pass B
finalAlternate = checkAlternate(user);
// checkAlternate(B) will traverse B->C until it finds C, so when
// this method returns, finalAlternate should be equal to C.
// After the second iteration we have approveMap.put(C, B); // here is the problem
approverMap.put(finalAlternate.getId(), user.getId());
}
}
If and only if, your list is sorted in such a way that grandparents occur before parents then a simple check for containsKey should do the trick:
if(!approveMap.containsKey(finalAlternate.getId()) {
approverMap.put(finalAlternate.getId(), user.getId());
}
However I don't know if this will help you much since in the list a grandparent might show up after a parent for example [B, A, C] will give you the "correct" output. To address this issue, you can add a parent field to each User and then you can check whether or not that User is a grandparent by setting the parent of each grandparent User to null:
public class User {
private User parent = null; // all grandparent users should have parent = null;
// .. some good code
public boolean isGrandparent() {
return parent == null;
}
}
Then you can add that comparison
if(user.isGrandparent()) {
approverMap.put(finalAlternate.getId(), user.getId());
}

You store the Users you have created inside a hashMap and give each user a unique identifier, i chose to use an integer that increases by 1 each time it's used.
Here is a sample implementation just to get you started:
public class User {
private static final HashMap<Integer, User> hashMap = new HashMap();
private static int index = 0;
private static int NO_PARENT = -1;
public final String name;
public final int id;
public final int parentId;
public User(String name) {
this.name = name;
this.id = ++index;
this.parentId = NO_PARENT;
hashMap.put(id, this);
}
public User(String name, int parentId) {
this.name = name;
this.id = ++index;
this.parentId = parentId;
hashMap.put(id, this);
}
private User getGrandParent(User u, int generation) {
if (generation == 2)
return u;
if (u != null && u.parentId != NO_PARENT)
return getGrandParent(hashMap.get(u.parentId), generation +1);
return null;
}
public User getGrandParen() {
return getGrandParent(this, 0);
}
}
Test
public static void main(String[] args) {
User u1 = new User("A");
User u2 = new User("B", u1.id);
User u3 = new User("C", u2.id);
User u4 = new User("D", u3.id);
System.out.println("grandparent of C is: " + u3.getGrandParen().name);
System.out.println("grandparent of D is: " + u4.getGrandParen().name);
}
Output:
grandparent of C is: A
grandparent of D is: B
Note that you would have to flush the HashMap of Users that you no longer need.
It wasn't clear to me what your userMQService did, if it's asynchronous task it's a whole nother ball game but you specificed HashMap and array so I assumed you wanted something like this.
To get the first ancestor you do:
private User getFirstAncestor(User u) {
if (u != null && u.parentId != NO_PARENT)
return getFirstAncestor(hashMap.get(u.parentId));
return u;
}
public User getFirstAncestor() {
if (parentId == NO_PARENT)
return null; // there is no ancestry.
return getFirstAncestor(this);
}
Here is another example that doesn't modify the User class:'
public class UserAncestry {
private static final HashMap<User, User> mapParent = new HashMap<>();
public static void setParent(User child, User parent) {
mapParent.put(child, parent);
}
public static User getParent(User user) {
return mapParent.get(user);
}
public static User getFirstAncenstor(User user) {
User parent = mapParent.get(user);
if (parent != null)
return getFirstAncenstor(parent);
return user;
}
}
public static void main(String[] args) {
User u1 = new User("A");
User u2 = new User("B");
User u3 = new User("C");
User u4 = new User("D");
UserAncestry.setParent(u2, u1);
UserAncestry.setParent(u3, u2);
UserAncestry.setParent(u4, u3);
User uu1 = UserAncestry.getFirstAncenstor(u4);
User uu2 = UserAncestry.getFirstAncenstor(u3);
System.out.println("uu1:: " + uu1.name);
System.out.println("uu1:: " + uu2.name);
}

Related

Updating the value of arraylist

I have a static data inside my arraylist in a controller package. These are my codes in the controller package.
for(int i=0;i<studentPic.length;i++){
//i want to update the value of zero
mStudentModels.add(new StudentModel(studentPic[i],status[i],studentName[i],courseAndYear[i],0));
}
public List<StudentModel> getStudentModels (){
return mStudentModels;
}
Now i want to update a certain data if it meets a certain condition:
private void stopCountdown() {
if (mTask != null) {
mTask.interrupt();
List<StudentModel> studentModels = studentData.getStudentModels();
studentData = new StudentData();
for(int i=0;i<studentModels.size();i++){
StudentModel studentModel = studentModels.get(i);
if(studentModels.get(i).getStatus()=="PRESENT"){
mFirebaseDatabase.child("attendance").child(formattedDate).child("present").push().setValue(studentModel);
}else if(studentModels.get(i).getStatus()=="LATE"){
mFirebaseDatabase.child("attendance").child(formattedDate).child("late").push().setValue(studentModel);
}else{
//i want to update the value of zero here
int absences = studentModel.getNumOfAbsences();
studentModel.setNumOfAbsences(absences+1);
mFirebaseDatabase.child("attendance").child(formattedDate).child("absent").push().setValue(studentModel);
}
}
}
}
The problem is if i call studentData.getStudentModels(); the value always remains zero. Whats the problem with that?
Here's my controller:
public class StudentData {
private List<StudentModel> mStudentModels;
public void setmStudentModels(List<StudentModel> mStudentModels) {
this.mStudentModels = mStudentModels;
}
public StudentData(){
mStudentModels = new ArrayList<>();
int[] studentPic = {R.drawable.boy1, R.drawable.boy2, R.drawable.girl1, R.drawable.girl2, R.drawable.girl3,
R.drawable.girl4, R.drawable.girl5, R.drawable.boy3, R.drawable.girl6, R.drawable.girl7,
R.drawable.boy4, R.drawable.girl8, R.drawable.girl9, R.drawable.girl10, R.drawable.boy5,
R.drawable.girl1, R.drawable.girl12, R.drawable.girl13, R.drawable.boy6, R.drawable.girl14};
String[] status = {"ABSENT","LATE","PRESENT","PRESENT","PRESENT","PRESENT","PRESENT","PRESENT","PRESENT","PRESENT","PRESENT","PRESENT",
"PRESENT","PRESENT","PRESENT","ABSENT","PRESENT","PRESENT","PRESENT","PRESENT"};
String[] studentName = {"Andy Lim", "Benjamin Adams", "Karen Healey", "Anne Pierre", "Corine Alvarez",
"Emily Hedrick", "Courtney Quick", "Oscar Renteria", "Ellen Joy", "Jesse Ramer",
"Jackson Beck", "Alicia Hofer", "Jenae Rupp", "Allison Beitler", "Martin Hofkamp",
"Emma Ruth", "Kathryn Berg", "Michelle Salgado", "Lewis Caskey", "Elizabeth Core"};
String[] courseAndYear = {"BSIT-3", "BSIT 2", "BSIT-3","BSCS-3" , "BSCS-2", "BSIT-3", "BSIT-2", "BSIT-3", "BSIT-2", "BSIT-3",
"BSCS-3", "BSCS-2", "BSCS-3", "BSCS-2", "BSCS-3", "BSIT-3", "BSCS-2", "BSIT-2", "BSCS-3", "BSCS-2"};
for(int i=0;i<studentPic.length;i++){
mStudentModels.add(new StudentModel(studentPic[i],status[i],studentName[i],courseAndYear[i],0));
}
}
public List<StudentModel> getStudentModels (){
return mStudentModels;
}
}
My model looks like this:
public StudentModel(int studentPic, String status, String studentName, String courseAndYear, int numOfAbsences) {
this.studentPic = studentPic;
this.status = status;
this.studentName = studentName;
this.courseAndYear = courseAndYear;
this.numOfAbsences = numOfAbsences;
}
Looks like below checks need to do:
Whether studentPic is not empty.
Whether mStudentModels is not empty (Mainly whether mStudentModels is getting added before the call of stopCountdown() method).
If it does not fix the issue, please provide more information on the code of Controller side.

recursive call in looping a list

I m trying to loop a list of users to find a person. Every person has a friends list. So i m using recursive call to check if the person is in someones friends list.
My Junit test is look like
#Test
public void IsInFriendsCicle() throws UserAlreadyInFriendListException, NoFriendFoundException, UsersNotConnectedException {
User one = new UserImpl("John","Snow");
User two = new UserImpl("Richard","Gerns");
User three = new UserImpl("Natalie","Portman");
User four = new UserImpl("Brad","Pitt");
User five = new UserImpl("Angelina","Jolie");
one.addFriend(two);
two.addFriend(three);
three.addFriend(four);
four.addFriend(five);
assertTrue(one.isInFriendsCycle(five, one.getFriends(), new Stack()));
}
So as it can be seen here, i want to know if Angelina is in the friends list of john. So it supposed to give back true.
The responsible method is for that :
public boolean isInFriendsCycle(User userToFind, ArrayList<User> list, Stack stack){
Stack s = stack;
ArrayList<User> groupList = list;
if(groupList.contains(userToFind)){
return true;
}else{
for (User user : groupList) {
if(!s.contains(user)){
s.push(user);
if(user.getFriends().contains(userToFind)){
return true;
}else{
return isInFriendsCycle(userToFind, user.getFriends(), s);
}
}
}
}
return false;
}
So the class is :
public class UserImpl implements User{
private String name;
private String surname;
private static int count = 0;
private int id;
private ArrayList<User> friends;
private ArrayList<Message> messagebox;
final static Logger logger = Logger.getLogger(UserImpl.class);
public UserImpl(String name, String surname) {
this.name = name;
this.surname = surname;
this.id = ++count;
this.friends = new ArrayList<User>();
this.messagebox = new ArrayList<Message>();
}
#Override
public User addFriend(User person) throws UserAlreadyInFriendListException,IllegalArgumentException{
if(this.getFriends().contains(person)){
throw new UserAlreadyInFriendListException("user is already in the friendlist");
}else if(person == null || this.equals(person) ){
throw new IllegalArgumentException("parameter is null or user trying to add himself as friend");
}else{
this.getFriends().add(person);
person.getFriends().add(this);
logger.debug(this.name + " added the user "+person.getName());
return person;
}
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UserImpl other = (UserImpl) obj;
if (this.id != other.id) {
return false;
}
return true;
}
}
There is a problem with stack somehow. I m using it to mark the persons so i dont get in the infinitive loop. There is a reason for passing user.getFriends() so it should stay in that way.
Any help will be appreciated !
replace
return isInFriendsCycle(userToFind, user.getFriends(), s);
with
if (isInFriendsCycle(userToFind, user.getFriends(), s)) return true;
As you have it, you prematurely exit if you didn't find it in the first branch of the recursive call. You don't want that - you want to continue until you find it, or there is nothing left to search through.
As an aside - your unit test wasn't helping you as you made the nesting too deep. If you had a few unit tests, first testing a friend-friend, then a friend-friend-friend, etc., you would have started to see where it was going wrong.
Also, as another aside: I would not use Stack (it is a legacy class) use Deque instead, which is the Java 6+ replacement. However in this case I would use a Set<User> in the form HashSet<User> as it fits your use case and probably performance requirements. I would also make the list variable types a List<User> not an ArrayList<User> inside your UserImpl class and isInFriendsCycle method, just to concentrate on the contracts and not the implementation.
I'd implement it as follows:
private Set<User> friends = new HashSet<User>();
public void addFriend(User friend) {
friends.add(friend);
}
public boolean isImmediateFriend(User user) {
return friends.contains(user);
}
public boolean isInFriendNetwork(User user) {
Set<User> visited = new HashSet<>();
List<User> stack = new LinkedList<>();
stack.push(this);
while (!stack.isEmpty()) {
User current = stack.removeFirst();
if (current.isImmediateFriend(user)) {
return true;
}
visited.add(current);
for (User friend : current.getFriends()) {
// never visit the same user twice
if (!visited.contains(friend)) {
stack.addLast(friend);
}
}
}
return false;
}
Pseudocode for the recursive algorithm with marking:
IsFriendOf(A, B):
if A == B:
return True
B.Marked= True
for all C in B.Friends:
if not C.Marked and IsFriendOf(A, C):
B.Marked= False
return True
B.Marked= False
return False

How to compose streams\Observables correctly

I have conceptual problem understanding how to compose between streams\Observables which have different return type.
Here is a draft method I'm trying to code:
public void findSeat() {
rx.Observable<GameObject> userObs = context.getUser();
rx.Observable<ActiveGame> gameObs = context.findGame();
rx.Observable.zip(userObs, gameObs, (userObj, game) -> {
User user = ...;
final List<Object> results = new ArrayList<Object>(3);
if(userObj.getStatus() != ErrorCodes.STATUS_OK) {
results.add(-1);
return results;
}
...
...
//***********************************
// THE PROBLEM IS HERE:
// "context.getActiveGameManager().updateGame(game)" returns Observable<GameOBject> and not List<Object> like .zip() expects.
// because of that I cannot do:
// "return context.getActiveGameManager().updateGame(game);"
// How can I do this convertion from Observable<GameObject> to List<Object>
//************************************
context.getActiveGameManager().updateGame(game)
.map((gameObj) -> {
if(gameObj.getStatus() != ErrorCodes.STATUS_OK) {
results.add(-2);
return (Observable<? extends Object>) results;
}
results.add(ErrorCodes.STATUS_OK);
results.add(user);
results.add(gameObj);
return gameObs;
});
return Observable.empty();
}).subscribe((results) -> {
int status = (int) results.get(0);
User user = (User) results.get(1);
ActiveGame game = (ActiveGame) results.get(2);
replyObj.reply(new JsonObject()
.putString("action", CommandActions.FIND_SEAT)
.putNumber("status", status);
.putNumber("game_id", game.getGameId())
);
});
}
The flow is as follow:
1. emit 2 Observable using .zip method.
2. do some logic on the return value of streams and if it results in error-code --> put it in list and return it so "subscribe" can return the error to user.
3. if no error, emit another "update" method using flatMap() - and this is where I have my problem.
4. eventually, all the results should be processed in "subscribe" because this is the point I acknowledge the user about his request.
Hope it's clear enough...
by the way, I'm trying to learn rxJava, but it's very hard I find there are enough\good sources - can someone recommend to me the best way to learn it?? I trying looking at tutorials at Youtube, Wikipedia, Github...most of them teaches using Scala and other scripting languages - couldn't find anything in Java.
Thank you for everyone that put the effort trying understand it!!
I think you were almost there, but try breaking down the code inside your .zip lambda into smaller Rx operations. For example:
rx.Observable
.zip(userObs, gameObs, (userObj, game) -> {
// Combine the user & game objects and pass them to the
// next Rx operation.
return new UserAndActiveGame(userObj, game);
})
.filter(userAndActiveGame -> {
// Remove this filter if you want errors to make it to the subscriber.
return userAndActiveGame.getUserObj().getStatus() == ErrorCodes.STATUS_OK;
})
.flatMap(userAndActiveGame -> {
// Remove this check if you filter errors above.
if (userAndActiveGame.getUserObj().getStatus() != ErrorCodes.STATUS_OK) {
return Observable.just(new FindSeatResult(-1));
}
return context.getActiveGameManager().updateGame(userAndActiveGame.getGame())
.map(gameObj -> {
if (gameObj.getStatus() != ErrorCodes.STATUS_OK) {
return new FindSeatResult(-2);
}
User user =...; // Whatever you are doing to get this in your example code.
return new FindSeatResult(ErrorCodes.STATUS_OK, user, gameObj);
});
})
The following classes are used for passing intermediate and final results:
private class UserAndActiveGame {
private final GameObject userObj;
private final ActiveGame game;
public UserAndActiveGame(GameObject userObj, ActiveGame game) {
this.userObj = userObj;
this.game = game;
}
public GameObject getUserObj() {
return userObj;
}
public ActiveGame getGame() {
return game;
}
}
private class FindSeatResult {
private final int status;
private final User user;
private final ActiveGame game;
public FindSeatResult(int status) {
this(status, null, null);
}
public FindSeatResult(int status, User user, ActiveGame game) {
this.status = status;
this.user = user;
this.game = game;
}
public User getUser() {
return user;
}
public int getStatus() {
return status;
}
public ActiveGame getGame() {
return game;
}
}
Your subscriber then uses the packaged result similar to what you are already doing.
.subscribe((results) -> {
// You don't need this if you filter errors above.
if (findSeatResult.getStatus() == -1) {
return;
}
int status = findSeatResult.getStatus();
User user = findSeatResult.getUser();
ActiveGame game = findSeatResult.getGame();
replyObj.reply(new JsonObject()
.putString("action", CommandActions.FIND_SEAT)
.putNumber("status", status);
.putNumber("game_id", game.getGameId())
);
});
By using the intermediate and final results classes instead of passing around your results in a List<Object> your code is much more forgiving to changes and the compiler will type check everything for you.

Grails: GORM: Traversing Many To Many Relationships

I have 2 domain objects, User and SystemRights (It's a many to many, so 1 user can have many rights and 1 right can be owned by many users). I'm looking for a simple way to check if a user has the required rights.
User Domain
class User {
static hasMany = [systemRights: SystemRight, enterpriseUsers: EnterpriseUser]
String email;
String passwordHash;
}
SystemRight Domain
class SystemRight {
public static final String LOGIN = "LOGIN"
public static final String MODIFY_ALL_ENTERPRISES = "MODIFY_ALL_ENTERPRISES"
public static final String ADMINISTER_SYSTEM = "ADMINISTER_SYSTEM"
public static final String VALIDATE_SUPPLIER_SCORECARDS = "VALIDATE_SUPPLIER_SCORECARDS"
static hasMany = [users:User]
static belongsTo = User
String name
}
The following did not work for me:
In User.class
public boolean hasRights(List<String> requiredRights) {
def userHasRight = SystemRight.findByUserAndSystemRight (this, SystemRight.findByName(requiredRight));
// Nor this
def userHasRight = this.systemRights.contains(SystemRight.findByName(requiredRight));
}
Current Horrible Solution
public boolean hasRights(List<String> requiredRights) {
for (String requiredRight : requiredRights) {
def has = false
for (SystemRight userRight : user.systemRights) {
if (userRight.name == requiredRight) {
has = true
break;
}
}
if (has == false) {
return false;
}
}
return true
}
If you're able/willing to change things up a bit, I'd highly recommend doing the following. It will make you're life so much easier.
First, remove the hasMany for SystemRight and User from both Domains and remove the belongsTo User from SystemRight.
Next, create the Domain to represent the join table.
class UserSystemRight {
User user
SystemRight systemRight
boolean equals(other) {
if (!(other instanceof UserSystemRight)) {
return false
}
other.user?.id == user?.id && other.systemRight?.id == systemRight?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (user) builder.append(user.id)
if (systemRight) builder.append(systemRight.id)
builder.toHashCode()
}
// add some more convenience methods here if you want like...
static UserSystemRight get(long userId, long systemRightId, String systemRightName) {
find 'from UserSystemRight where user.id=:userId and systemRight.id=:systemRightId and systemRight.name=:systemRightName',
[userId: userId, systemRightId: systemRightId, systemRightName: systemRightName]
}
}
Then, in your User class you can add this method:
Set<SystemRight> getSystemRights() {
UserSystemRight.findAllByUser(this).collect { it.systemRight } as Set
}
Then, add this to your SystemRight Domain:
Set<User> getUsers() {
UserSystemRight.findAllBySystemRight(this).collect { it.user } as Set
}
For a more detailed explenation of why this approach is full of win, aside from actually solving your problem, take a gander at this.
I would definitely try to solve this in the database.
def relevantUserRights = SystemRight.withCriteria {
eq("user", this)
"in"("name", requiredRights);
}
return relevantUserRights.size() == requiredRights.size()
How about the following?
public boolean hasRights(List<String> requiredRights) {
return null != (this.systemRights.find { requiredRights.contains(it) });
}
(Not tested: Groovy newbie here)

ArrayList of custom Java objects over BlazeDS into AS3.0

Right away i just try to explain my problem:
Using BlazeDS i got the following Javaclasses:
DatabaseService.java:
public class Database {
private Category helpCat = null;
private Category root = new Category(1, "root", null, null);
private List<Article> database;
public Database()
{
// ------------ tree -----------------------------------------------------------------------
List<Category> level_one = new ArrayList<Category>();
List<Category> level_two_computer = new ArrayList<Category>();
List<Category> level_tree_hardware = new ArrayList<Category>();
// Level 1
Category buecher = new Category(2, "buecher", root, null);
Category computer = new Category(3, "computer", root, level_two_computer);
level_one.add(buecher);
level_one.add(computer);
//Level 2
Category hardware = new Category(4, "hardware", computer, level_tree_hardware);
Category software = new Category(5, "software", computer, null);
level_two_computer.add(hardware);
level_two_computer.add(software);
//Level 3
Category graphic = new Category(6, "graphic", hardware, null);
Category sound = new Category(7, "sound", hardware, null);
level_tree_hardware.add(graphic);
level_tree_hardware.add(sound);
// Level 0
root.addChilds(level_one);
// ------ tree end ----------------------------------------------------------------------------
database = new ArrayList<Article>();
try {
add(new Book("Per Anhalter durch die Galaxis", "42", Articletype.BOOK, 795, "Per Anhalter durch die Galaxiss", "Douglas Adams", "Heyne Verlag", "Taschenbuch", "3453146972"), buecher);
add(new Book("Harry Potter und der Stein der Weisen", "descriptionShort", Articletype.BOOK, 1299, "Harry Potter und der Stein der Weisen", "Joanne K. Rowling", "Carlsen Verlag GmbH", "gebunden", "3551551677"), buecher);
add(new Book("Harry Potter und die Kammer des Schreckens", "descriptionShort", Articletype.BOOK, 1499, "Harry Potter und die Kammer des Schreckens", "Joanne K. Rowling", "Carlsen Verlag GmbH", "gebunden", "3551551677"), buecher);
add(new Hardware("nVidia GeForce 8400GS", "Graphikkarte", Articletype.HARDWARE, 2665, "512 GDDR5 Speicher, DVI, 1 GPU", "MSI", "neu"), graphic);
add(new AKW("Biblis C", "Druckwasserreaktor, Preis auf Anfrage, Nur Selbstabholer", Articletype.AKW, -1, "Biblis", 0, 2525, "Siemens", 1, 2012), software);
} catch (Exception e) {
e.printStackTrace();
}
}
public List<Category> getCategories(String node) {
if(node.equalsIgnoreCase("root"))
return root.getChildren();
Category baum = null;
baum = get_node_by_name(root, node);
return baum.getChildren();
}
private Category get_node_by_name(Category localroot, String lookfor)
{
helpCat = null;
if(localroot.getChildren() != null)
{
for (int i = 0; i < localroot.getChildren().size(); ++i)
{
if(!(localroot.getChild(i).getName().equals(lookfor)))
{
get_node_by_name(localroot.getChild(i), lookfor);
}
else
{
helpCat = localroot.getChild(i);
helpCat.setParent(null);
}
}
}
return helpCat;
}
public List<Article> search(int artID, String name, Category categorie){
List<Article> ergebnis = new ArrayList<Article>();
if (artID >= 0)
{
for(int i = 0; i< database.size(); ++i){
if(database.get(i).getID() == artID)
{
ergebnis.add(database.get(i));
return ergebnis;
}
}
}
if (name != null){
for(int i = 0; i<database.size(); ++i){
if (database.get(i).getName().equalsIgnoreCase(name))
ergebnis.add(database.get(i));
}
return ergebnis;
}
if (categorie != null){
{
ergebnis.addAll(categorie.getArticles());
}
return ergebnis;
}
return database;
}
public Article add(Article newArticle, Category cat) throws Exception
{
newArticle.addCategory(cat);
if(newArticle.getID() != 0)
{
throw new Exception("Die Artikel ID wird vom DBS festgelegt!");
}
if (database.isEmpty())
{
newArticle.setID(0);
}
else
{
newArticle.setID(database.get(database.size() - 1).getID()+1);
}
database.add(newArticle);
return newArticle;
}
}
And the Category Class:
public class Category {
private int idCat;
private String nameTEST;
private Category parent = null;
private List<Article> articles = new ArrayList<Article>();
private List<Category> children = new ArrayList<Category>();
public Category(int _id, String _name, Category _parent, List<Category> _children)
{
if(_id > 0)
idCat = _id;
if(_name != null)
nameTEST = _name;
if(_parent != null)
parent = _parent;
if(_children != null)
children = _children;
}
public String toString()
{
return nameTEST;
}
void addArticle(Article article){
articles.add(article);
}
public List<Article> getAllArticles(){
List<Article> ergebnis = this.getArticles();
for (int i = 0; i<children.size();++i){
ergebnis.addAll(children.get(i).getAllArticles());
}
return ergebnis;
}
public void setID(int iD) {
idCat = iD;
}
public int getID() {
return idCat;
}
public void setName(String name) {
this.nameTEST = name;
}
public String getName() {
return nameTEST;
}
/**
* #param parent the parent to set
*/
public void setParent(Category parent)
{
this.parent = parent;
}
/**
* #return the articles
*/
public List<Article> getArticles()
{
return articles;
}
public void addChilds(List<Category> _next)
{
for (int i = 0; i < _next.size(); ++i)
{
children.add(_next.get(i));
}
}
public void addChild(Category one_next)
{
children.add(one_next);
}
public Category getChild(int index)
{
return children.get(index);
}
public void removeChild(Article article){
articles.remove(article);
}
public List<Category> getChildren()
{
return this.children;
}
}
also there are of course classes for articles and so on, but thats not important at that point.
the counterpart in flex looks like this:
Category.as
[RemoteClass(alias="PACKAGE.Category")]
public class Category
{
private var idCat:int = -1;
private var nameTEST:String = null;
private var parent:Category = null;
private var articles:ArrayCollection = new ArrayCollection;
private var children:ArrayCollection = new ArrayCollection;
public function Category(id:int, name:String, parent:Category, childlist:ArrayCollection, articles:ArrayCollection = null)
{
this.idCat = id;
this.nameTEST = name;
this.parent = parent;
this.articles = articles;
this.children = childlist;
}
public function setChildren(childList:ArrayCollection):void
{
this.children = childList;
}
public function getChildren():ArrayCollection
{
return this.children;
}
public function getName():String
{
return this.nameTEST;
}
}
Then i got a Flex service class calling BlazeDS and executing the getCategories java method. Since Flash dosn't seem to understand typed arrays, the result from that method which i get back in flex is a simple array of untyped objects (the mapping dosn't seem to work here, even tought the class category exists in flex and has the same properties).
thats the first thing. but however, i'm converting the untyped objects manually into objects of the category.as class.
the second thing is that categories have child-categories within the java object, which are also ArrayLists of the type category.java. the problem about that: my result event object only contains the first level of categories, looking into them the children are allways null. i dunno why they are empty, since they ARE part of the java object category.
and the third thing (the strangest by fast), you maybe noticed i named the properties of the category.java class strange, like idCat and nameTest instead of simply id and name. why that? because the property names of my flex result objects dont seem to change when i change the java objects properties names (result object properties are named "id" and "name" but the java class object properties are named "idCAT" and "nameTEST"). that it REALLY strange, since if i set the properties, like you see at nameTEST = "TESTNAME" it IS recogniced by flex, only the proertyNAMES dont seem to be recognized at all.
is blaze DS saving / caching the mapping configuration somewhere? how do i get it to rebuild the hole mappings IF so?
that could also explain my problem about the untyped objects i get from java, since before i changed the lists into ArrayLists they where vectors ( which blazeDS dosn't support AFAIK), and maybe not only the propertynames, but also the propertytypes are hard-mapped at some wired place and blazeds just dosn't get them refreshed.
i really like checked everything 5 times by now, even redeployed blazeds on the server to make sure no mappings left, but it didnt help at all.
ANY ideas what i could do? (exept changing to another serializer then blazeds (thats what i'm going to do if everything else fails...))
i have the same issues, but if you can warm up the tree before call the method, it will be ok.
what i mean "warm up" is you iterator the arraylist without doing anything. it is flunky why this work!
I have had similar problems with a list returned from a service not including the child elements in the list. I have found that BlazeDS can return a typed list. The two things that fixed this for me were:
a) Ensure that the returned list is of type java.util.List (not java.util.ArrayList for example).
b) Ensure that the class for the elements in the list have both public setters and getters for all entities to be returned.
For example - the following code works for me:
public class OrganisationService {
...
public List<Organisation> getOrganisations() {
List<Organisation> list = new ArrayList<Organisation>();
...
return list;
}
...
}
As mentioned elsewhere, you need to initiailize your AS3 remote objects so that it is included in the SWF during compilation.
Somewhere in your code, add:
var cat:Category = new Category();
var art:Article = new Article();
That should fix your generic object issue. (I add mine all in one spot, in an application start up method).
It turns out that a simple missmatch of the classnames was the cause of all evil. still some problems to solve, but atleast i get sub-arrays returned now, only the objects are still simple AS 3 objects and not the specified "Category" and "Article" objects, but i think thats because i dont have all methods included and mapping is failing because of that.
but thanks for your offer, i appreciate that.

Categories

Resources