Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord
Thanks for the quick responses. I've added the overloaded constructor to save on typing the parse so often (great idea). I'm glad nothing obviously better immediately jumped out in terms of my loop method for sorting the items. Overall this process is only going to deal with String arrays of a few hundred lines at most, so as long as the core of it looks okay that makes me feel better.

Adbot
ADBOT LOVES YOU

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

PierreTheMime posted:

My issue with this method is that I still feel there's a better way to verify which the line contains (task/predecessor) and assign it to the appropriate object. Is my simple loop/if logic okay or should I be considering something better? (My tasknum variable starts at 1 because the wfprof object already contains a "start" task as item 0 upon construction)

Right now my code is returning correct information, but I want to learn as much as I can through this whole ordeal so I'd love comments/opinions from more experienced people.

I guess the biggest thing that jumps out is the fact you have two if statements, which suggests they're separate checks - they could both be possible, which isn't correct right? If a line can only start with either Task or Predecessor, using an else if for the second check conveys your intent more clearly (although a quick comment at the start of each block saying what it's for would be a good idea too)

It would also be worth throwing some error handling in there - logging that you've hit a line that doesn't fit anything you expect, catching parsing errors and making sure they fail cleanly. Even if you have full control over the data and you're sure it will never be malformed :thumbsup: you could potentially get corruption, and that means errors and exceptions crashing your program.

This is probably overkill, and people can criticise my terrible coding, but here's another way of doing it

Java code:
class LineParser {

    void doStuff() {

        // constants defining formatting for your data
        final String TASK_HEADER = "Task";
        final String PREDECESSOR_HEADER = "Predecessor";
        final String SEPARATOR = ":::";

        // holds the most recent task, starts null so we can ensure a predecessor line comes after a task
        WorkflowTask currentTask = null;

        for (String line : array) {
            String[] elements = line.split(SEPARATOR);
            if (elements.length == 0) {
                // got an empty line! Just going to ignore it and move on
                continue;
            }
            String header = elements[0];

            // work out what type of data this line holds, and try to parse it
            if (header.equals(TASK_HEADER)) {
                // got a task description, try to parse it
                try {
                    WorkflowTask newTask = WorkflowTask.parse(elements);
                    wfprof.addWorkflowTask(newtask);
                    currentTask = newTask;
                } catch (MyParseException e) {
                    // couldn't create a task - is this bad?
                }
            } else if (header.equals(PREDECESSOR_HEADER)) {
                if (currentTask == null) {
                    // got a predecessor without a preceding task! Now what
                } else {
                    try {
                        Predecessor newPred = Predecessor.parse(elements);
                        currentTask.addPredecessor(newPred);
                    } catch (MyParseException e) {
                        // couldn't create a predecessor!
                    }
                }
            } else {
                // got a non-empty line without a task or predecessor header! Uh-oh?
            }
        }
    }
}


class WorkflowTask {

    static WorkflowTask parse(String[] configElements) throws MyParseException {
        WorkflowTask newtask = new WorkflowTask();
        try {
            newtask.setTaskname(configElements[1]);
            newtask.setColumn(Integer.parseInt(configElements[2]));
            newtask.setLnr(Integer.parseInt(configElements[3]));
            newtask.setRow(Integer.parseInt(configElements[4]));
            return newtask;
        } catch (NumberFormatException e) {
            // handle bad data, expected an int and got something else
            throw new MyParseException();
        } catch (ArrayIndexOutOfBoundsException e) {
            // tried to access a missing data element
            throw new MyParseException();
        }
    }

}


class Predecessor {

    static Predecessor parse(String[] configElements) throws MyParseException {
        Predecessor newpred = new Predecessor();
        try {
            newpred.setLnr(Integer.parseInt(configElements[1]));
            newpred.setStatus(configElements[2]);
            return newpred;
        } catch (NumberFormatException e) {
            // handle bad data, expected an int
            throw new MyParseException();
        } catch (ArrayIndexOutOfBoundsException e) {
            // tried to access a missing data element
            throw new MyParseException();
        }
    }
}

class MyParseException extends Exception {
    // add whatever Exception methods you want to use, to provide info about the cause
}
I've done a couple of things differently - the main class handles identifying each line and breaking it up into its components, so it has those tokens defined at the top, all in one place, just for clarity and to make changing things easier. But once it's identified a line's type, all that data is passed to the class that handles that type. So basically, a WorkflowTask knows how to parse itself. The main LineParser class doesn't need to know anything about those internal details, just enough to see which class is responsible for taking care of it. If you ever change a WorkflowTask's structure, you should only need to poke around in that class, changing the parser.

So that makes your line parser flow a bit cleaner, especially if you ever have to add any extra line types. It also helps with all the extra exception handling, which obviously makes things a bit more complicated. You can definitely simplify it, catch multiple exceptions in one place etc, I just wanted to highlight some important cases where you need to decide what to do about them. If you can ignore stuff or you want to immediately halt everything and fail, you can definitely wrap everything in a more general try/catch case, or just have the line parse method throw an exception. You get the idea hopefully!

Also tell me if I'm the bad programmer - I know it's a bit overengineered, but this is going into production right?

baka kaba fucked around with this message at 19:00 on Jun 21, 2016

FateFree
Nov 14, 2003

This is probably due to a weakness in Java's exception handling but I can't see the value to all of that exception code, it obscures everything that's happening in these methods, and in the end all its doing is throwing another exception class.

So obviously this depends on how rigorous you need to handle exceptions, but why not just catch and old fashioned runtime exception around those parse methods? Then at least the parse methods don't need to bother with the exception code, its not like they are providing any useful info with a custom exception class.

I guess I was just never a fan of custom exception classes unless they are part of an API, if something is a runtime exception just let it be a runtime exception and save yourself the code.

speng31b
May 8, 2010

runtime exceptions intentionally don't tell the callers that they're a condition which can occur. They're good for assert-type conditions, not so good for indicating that something exceptional happened which is recoverable and should be handled (perhaps in a specific way). when you use unchecked exceptions for things that you should be using checked exceptions for, you end up with generic catches all over the place that are just like "catch (Exception blah) {/*do nothing*/}". The exception usage in the code above seems fine for what it is, for Java, since the exceptions seem to be intended to be caught and handled (logged, or something).

By all means read up on the arguments for and against checked exceptions even being things that should exist, and whether or not Java is dumb and bad for having them, but that's another thing entirely.

speng31b fucked around with this message at 20:48 on Jun 21, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Well it was partly to illustrate the different cases you need to handle (invalid data, missing data) and then throw a general 'can't parse this' error for the main loop to catch, and make a decision on what to do. Log the bad line and carry on, or whatever

But yeah if you're happy just letting it crash because it needs to be fixed and perfect, just let the dangerous methods throw their runtime exceptions

e ^^^ yeah that's what I was going for basically

pigdog
Apr 23, 2004

by Smythe
Basically, avoid throwing checked exceptions. As you can see, they make the code ugly and are usually more pain in the rear end than they're worth. Quite a few people believe they shouldn't have been a part of the Java language in the first place. For example the very useful Stream API in Java 8 just balks at them. Not only are they ugly, but they also don't let the code be optimised quite as well by the VM, if that's important to you.

If there's an exceptional circumstance, throw a RuntimeException of some sort, which will always propagate up to the place where the application is ready to handle it.

ps: The code above illustrates the fact there's rarely anything useful anybody can do about the checked exceptions, if you choose to add them. Ok, so there may be a NumberFormatException, or the tasks may be in the wrong order. What is anybody supposed to do about that? Maybe you just consider the whole data bad, maybe you would take what was read until that point, maybe just ignore the bad bits. All of that could be handled without throwing a checked exception. In practice the custom exception just doesn't help at all.

pps: Whenever you catch an exception and throw another, then at the very least add the original exception as a cause to the new one. In

code:
} catch (NumberFormatException e) {
     // handle bad data, expected an int and got something else
     throw new MyParseException();
}
you lose the original exception and whatever was causing it, while it would often be quite useful for logging and debugging. Never lose data from exceptions, always add new data! If you have to do it, do it like this:
code:
} catch (NumberFormatException e) {
     throw new MyParseException(e);
}

pigdog fucked around with this message at 22:06 on Jun 21, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Yeah that's why I put that comment in the Exception block, I guess that wasn't very instructive if you're not used to using them though!

But really that's (probably?) the most overloaded example of dealing with the problem of bad data - it catches all the things that can go wrong, catches each case separately, and throws something that can be caught exactly where the problem occurs (like trying to create a new WorkflowTask or Predecessor). If you absolutely need to catch every potential error and do something intelligent with it, that's sort of what you have to do, right?

Definitely not saying you need to be that granular, or even catch exceptions at all, but there are some situations where you need to keep on truckin' and keep a record of what's gone wrong, so you can maintain a valid state and make sure everything's accounted for. So really it depends on what you need and what an error means for you (and if you're even likely to get any). I just wanted to throw (:v:) out an example of error handling in case Pierre thought it would be useful, it's a good thing to at least make a conscious design decision about

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

pigdog posted:

Maybe you just consider the whole data bad, maybe you would take what was read until that point, maybe just ignore the bad bits. All of that could be handled without throwing a checked exception. In practice the custom exception just doesn't help at all.

How would that look though? One of the things I like about exceptions is that you can just take a block of stuff that could potentially go wrong, wrap it in a try block, and take a general decision based on that happening. So instead of having to write a bunch of checking and validating code (which may be tied to other things, e.g. the array length check has to match on the number of variables you're assigning from it) you can just write it cleanly and not tolerate any failures.

What's the best way you could rewrite that parse() method in WorkflowTask, with error checking instead of exceptions? I'm genuinely curious, I try and avoid using exceptions but it seems like the cleanest and shortest way to handle that block - especially with a mix of types being assigned, so you can't easily check in a loop

oops I meant to edit this in

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord

baka kaba posted:

Yeah that's why I put that comment in the Exception block, I guess that wasn't very instructive if you're not used to using them though!

But really that's (probably?) the most overloaded example of dealing with the problem of bad data - it catches all the things that can go wrong, catches each case separately, and throws something that can be caught exactly where the problem occurs (like trying to create a new WorkflowTask or Predecessor). If you absolutely need to catch every potential error and do something intelligent with it, that's sort of what you have to do, right?

Definitely not saying you need to be that granular, or even catch exceptions at all, but there are some situations where you need to keep on truckin' and keep a record of what's gone wrong, so you can maintain a valid state and make sure everything's accounted for. So really it depends on what you need and what an error means for you (and if you're even likely to get any). I just wanted to throw (:v:) out an example of error handling in case Pierre thought it would be useful, it's a good thing to at least make a conscious design decision about

I really do appreciate the thorough examples. My code is going to be used in a test environment to stage for production after a thorough checkout and I do not foresee major issues once the initial setup is complete. All the data I'm feeding in is known-good info produced by a shell script I wrote earlier. Essentially I'm converting objects from one proprietary cockamamie scheduling system to another and there's going to be large parts of any given conversion that will need to be reviewed/revised or outright replaced. At this point, at least in the thorough testing phase, I'd actually like it to throw as many errors and I can come across so I can learn the ins-and-outs of this API. The conversion should save a solid 200-500 hours of work though, so there's what :v: I'll totally be saving this info for projects going forward though!

PierreTheMime fucked around with this message at 23:49 on Jun 21, 2016

FateFree
Nov 14, 2003

baka kaba posted:

Well it was partly to illustrate the different cases you need to handle (invalid data, missing data) and then throw a general 'can't parse this' error for the main loop to catch, and make a decision on what to do. Log the bad line and carry on, or whatever

But yeah if you're happy just letting it crash because it needs to be fixed and perfect, just let the dangerous methods throw their runtime exceptions

I wasn't saying let it crash, simply let it throw its RuntimeException and catch that instead of the MyParseException for a bad row. In the end you get the same protection with less code (no MyParseException class, no try catch stuff in those parse methods). Sure you might catch more than just a numberFormat or arrayoutofbounds error, but in this case I imagine you would want to catch anything that could go wrong since there isn't anything you can do about it anyway.

pigdog
Apr 23, 2004

by Smythe
^^ What he said.

baka kaba, I see where you're coming from. The creators of the language originally thought it would be a nice idea to let methods throw exceptions that the user has to explicitly deal with, thus provide multiple possible outputs, and ensure the user of the method covers all of them.

Instead:

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
:stare: Look at all those empty blocks

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

I know this isn't Pierre's case, but imagine the requirements were to parse all the data, cleanly ignore any invalid stuff (to keep the system running and in a consistent state), and to log the errors so there's an audit trail, and the bad data can be addressed instead of just disappearing.

In that scenario, it seems like you need separate try/catch blocks for each type of task anyway, since they need to be handled differently. If you fail to parse and create a WorkflowTask, you need to have the loop ignore any valid Predecessor lines that follow it, since their task doesn't exist. If you fail to parse a Predecessor line... maybe you can ditch it and just log it, or maybe you need to have the Task deleted (since it isn't going to have all its data) and log that.

I guess you could wrap the whole thing in a try/catch and then handle the errors at the end, but that means another if statement to work out which type of line you were dealing with when the error occurred, but that feels like you're repeating yourself. Definitely possible though, I'd probably prefer that if the code were longer / more indented

And the custom exception was really just a way of keeping the implementation details in the parsing methods - there could be multiple possible exceptions in the parsing code, but the caller doesn't need to know about any of that. Just trying to cut down on the number of exceptions the caller needs to worry about handling (and being explicit about it). Obviously if there's no handling, don't bother!

You could just return null but I'm trying to get away from doing that for exceptional errors :shobon:

Judge Schnoopy
Nov 2, 2005

dont even TRY it, pal

Zaphod42 posted:

If you want some direct tips for your current program, dump it on pastebin and I can point you in the right direction for re-engineering the classes.

You've been a huuuuuuuge help.

After getting all of your great advice, I completely overhauled my project and I'm much happier with it. Main{args} is simply "Control control = new Control();", and that's it.

A high level overview is as such:
Control holds the current level number and game score. It draws a main menu, takes the selection and pushes the program in the right direction.
control.startGame encapsulates the entire game loop from the first level to recreating the menu when the game is over.
In the main loop, class wordList handles the back-end logic. It takes a difficulty parameter and sets the master list to one of three array lists. Then, for every level that's created, it will randomly pick a word from that list (and record which selection was made so there are no repeats).
The level is created with the selected word, then waits for the user to type the word, evaluates for a match, if it matches the level passes a score back to Control and the level is destroyed.
Rinse and repeat 5 times at which time a final score is posted by Control.

I tried thinking of cohesion and coupling when designing the new classes. The main concept I was going for was for Control to be the info handler; none of the other classes should talk to each other, they should be called by and report back to Control, which will figure out where the info needs to go next. Only the GUI breaks this concept because I needed syncs and displayed information available immediately. In limiting coupling the best I could, it seemed cohesion fell into place since classes were designed to solely interact with their own information and provide methods for any changes that needed to be made.

Here's the entire project if you'd like to give it a look-over and let me know what my programming pitfalls are. I know the GUI needs an overhaul so I'm not drawing 15 different windows per playthrough but I'm thinking I hosed up starting with Swing jframes and not something more inclusive, like javafx
https://github.com/JudgeSchnoopy/typingGame

Current feature TODO list: persistent high score list stored in text file, sound for Correct and Wrong windows, more interesting GUI.

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Judge Schnoopy posted:

I tried thinking of cohesion and coupling when designing the new classes. The main concept I was going for was for Control to be the info handler; none of the other classes should talk to each other, they should be called by and report back to Control, which will figure out where the info needs to go next. Only the GUI breaks this concept because I needed syncs and displayed information available immediately. In limiting coupling the best I could, it seemed cohesion fell into place since classes were designed to solely interact with their own information and provide methods for any changes that needed to be made.

Very cool dude! Yeah, if you're thinking cohesion and coupling, working on one tends to make the other fall into place naturally, since they're so closely related.

Code looks pretty clean, I like it.

One thing that kinda jumped out at me, whenever I see magic numbers it makes me wanna replace them

code:
 case 1: main.dispose();
                    
                    this.startGame();
            case 2: ;
            case 3: System.exit(0);
Its not like, the end of the world, but it would be better if those were an enum instead.

So for a matter of readability, maintainability, etc. I would end up with:

code:
public enum MenuState {START(1), SOMETHINGELSE(2), EXIT(3)};


 case MenuState.START: main.dispose();
                    this.startGame();
 case MenuState.SOMETHINGELSE: ;
 case MenuState.EXIT: System.exit(0);
Then if you end up referring to those same values elsewhere in your code, you can have them all point at the same enum value, and then you can easily change those values in one place and have them automatically updated everywhere, if you decide you want to insert a 4th menu state or something later on, or re-arrange them.

Again, the way you did it isn't wrong, but it just helps with readability and stuff in the long run.

Plus it makes catching bugs easier; if you read "case: 1: System.exit(0);" that doesn't tell you anything, but if you read "case START: System.exit(0);" its obvious that isn't the right value.

Zaphod42 fucked around with this message at 20:31 on Jun 22, 2016

Failbaddon
Apr 30, 2015
I'm currently learning Java/Groovy and I'm trying to write code that will grab json data from DOAJ using its API. Usually this is not problem for me but this time I got following error:
code:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path
Code:

code:
public static void main(String[] args) {

        def url = "https://doaj.org/api/v1/search/articles/bibjson.abstract%3A%22shadow%22"
        def data = url.toURL().getText()

    }
I searched on Google and found that I have to import doaj.org cert using keytool. I have imported it but it still doesn't work :C
Anyone got an idea what I should try next?

Janitor Prime
Jan 22, 2004

PC LOAD LETTER

What da fuck does that mean

Fun Shoe
Where did you import it? usually you'll want to import it into your JRE installations truststore, or provide another truststore with the correct certificates.

Also if you have multiple JREs/JDKs installed then your program might be running with one that you didn't import the cert into.

Failbaddon
Apr 30, 2015

Janitor Prime posted:

Where did you import it? usually you'll want to import it into your JRE installations truststore, or provide another truststore with the correct certificates.

Also if you have multiple JREs/JDKs installed then your program might be running with one that you didn't import the cert into.

Thank you :D I was importing it into 1.8.0_92 instead of 1.8.0_91. It works now.

Jerry Bindle
May 16, 2003
Do you have to "Respect the Clip" when using JavaFX's Canvas like you do when overriding the paintComponent() method in swing? Can anyone point me towards a JavaFX resource like swing's "filthy rich clients"?

I'm seeing some tearing while drawing simple lines that follow the mouse cursor.

Boz0r
Sep 7, 2006
The Rocketship in action.
I'm doing some importing of CSV files, and converting them into objects, and I'm finding it pretty messy. Right now I'm doing something like this:

code:
	List<ReturnObjects> returnObjects = new ArrayList<ReturnObjects>();

    	String[] lines = data.split("\n");
	
	for (int i = 0; i > lines.length; i++)  {
		
		String[] parameters = line.split(";");

		if (validateParameters(parameters)) {
			returnObjects.add(new ReturnObject(parameters[0], parameters[1], ..., parameters[n]);

			or...
	
			returnObjects.add(new ReturnObject(parameters));
		}
	}
The ReturnObject class is pretty much just a struct, with a lot of fields. Is there a smarter way of doing this? Can I define some sort of mapping directly from the CSV file to the struct class?

EDIT: My workplace uses JBoss 4.2.3. How dumb is that?

Boz0r fucked around with this message at 10:18 on Jun 30, 2016

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...
If the CSV has the column names as the first line (and really it ought to), consider using a Map as your per-line data structure.

Also, reading the entire file and then splitting it into lines yourself is wasteful, and prone to fail on large files. Use a BufferedReader to pull a line at a time from your input source.

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope
Without even googling, I'm going to guess that there is a CSV parsing library for Java that will do a better job of handling quoted values and similar cases better than a roll-your-own version.

There is probably one that can automatically map the columns of the file to members in your class and then return some kind of List<YourDataObject> from the file.

Common file format + common programming language = there's a library for that.

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

Yeah, are you sure you can't use the Apache Commons parser or another library? There can actually be quite a bit of vagaries even in CSV and it'd be so much easier to farm that out to a library than tediously maintain a pile of code that just hastily solves a very common problem.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The problem with using a csv library is finding the one that best corresponds to whatever bespoke csv-like format you actually have.

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

And if it turns out to be just Excel format anyway, a little bit of research actually saves you time. Amazing how that works.

smackfu
Jun 7, 2004

I have a Product class. I also have a List<Product> that contains all the products that belong to someone. I have some methods that operate on the list.

Why would it be a bad idea to create a new ProductList class that extends List<Product> and put the methods in that object, instead of the controller? It feels like not a common pattern in Java but I'm not sure why.

Edit: I think I see why I am getting messed up. Normally you would have a User object and that would contain (not extends) the List of Products and you would have methods on the User. In this case I just have the free floating list. So I probably should just create a User to make it a proper domain model.

smackfu fucked around with this message at 21:41 on Jul 1, 2016

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

smackfu posted:

I have a Product class. I also have a List<Product> that contains all the products that belong to someone. I have some methods that operate on the list.

Why would it be a bad idea to create a new ProductList class that extends List<Product> and put the methods in that object, instead of the controller? It feels like not a common pattern in Java but I'm not sure why.

Edit: I think I see why I am getting messed up. Normally you would have a User object and that would contain (not extends) the List of Products and you would have methods on the User. In this case I just have the free floating list. So I probably should just create a User to make it a proper domain model.

Yeah, you're getting it with the edit. You *could* make a ProductList extends List, but then we start to get into the whole cohesion thing. Now you've got a class that is a container that also has business logic, and are you actually overloading any of the container methods? If so, then why? If you had a real specific use case that could make sense maybe, but even for special data structures it'd usually be better to divide it into the container class and then the business logic class. Having that clear divide between "here is the data manipulation logic" and "here is the business logic" is a good thing.

If its actually a new container type, then making it ProductList extends List<Product> limits it to that use case. If you were making a new container, it would be more useful to make the new extended List container object generic, so you could use it in the future with other objects that aren't Products. Then Product-specific business logic goes somewhere else.

What is usually done like you said in the edit is to have a ProductList class that does not extend List but simply has a List member variable, and the methods to manipulate it.

pigdog
Apr 23, 2004

by Smythe

Zaphod42 posted:

What is usually done like you said in the edit is to have a ProductList class that does not extend List but simply has a List member variable, and the methods to manipulate it.

This. Don't try to extend the List, use it as a member field. If it's no longer a list, but has methods that operate on that list doing stuff, then it's probably no longer a list, is it? And if you really want to use say add() or get() methods on that List, then you can create delegate methods that call the ones on the List. IDEA can autogenerate them for you with Alt-Insert -> Delegate Methods , Eclipse probably can too. It looks like a lot of boilerplate, and perhaps it is, but it also gives you a ton of flexibility to, say, change the List to something else behind the curtains.

quote:

Edit: I think I see why I am getting messed up. Normally you would have a User object and that would contain (not extends) the List of Products and you would have methods on the User. In this case I just have the free floating list. So I probably should just create a User to make it a proper domain model.
That's strictly a guess about your domain, but a User object probably shouldn't contain a list of Products in any context I could think of. Maybe you'd like an Invoice or Account or something, which has a list of products and references the user's identity.

pigdog fucked around with this message at 22:51 on Jul 1, 2016

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
Purchase history? :shrug: Users and Accounts can be separate, but depending upon the context it may not be necessary.

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord
How do people normally go about verifying arguments prior to executing the main method? I'm building an export utility and currently just have it call a "checkArgs" static method as the first step, passing the args in and testing for invalid uses beforehand. Additionally, how do people go about setting up the generic "help" display for simple command-line applications? I currently have it set it in checkArgs to output the generic help info if no arguments are passed or if any args contain "help" or "HELP", but I'm not sure if there's a simpler/better way to go about it.

venutolo
Jun 4, 2003

Dinosaur Gum

PierreTheMime posted:

Additionally, how do people go about setting up the generic "help" display for simple command-line applications? I currently have it set it in checkArgs to output the generic help info if no arguments are passed or if any args contain "help" or "HELP", but I'm not sure if there's a simpler/better way to go about it.

Commons CLI is likely worth looking at. Google for examples.

If you only have one argument, like expecting a single int, then Commons CLI is probably overkill.

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord

venutolo posted:

Commons CLI is likely worth looking at. Google for examples.

If you only have one argument, like expecting a single int, then Commons CLI is probably overkill.

No, I have multiples of varying data types. This looks like it will be useful, at the very least to standardize things. Thanks.

CarrKnight
May 24, 2013
JCommander is another library that helps with main arguments. This is an example of how to code the help case.

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord
Now that I've gotten the backend working for an export/import utility, I want to work out a little GUI to avoid frightening people with command line or calling it from an object inside the tool itself. What would people's preferred GUI method for basic applications? I'm already starting in with Swing and getting "okay" results but I didn't want to dig in too far if there's a consensus there's a better option.

I basically just need it to populate a list and allow the user to highlight what they want, check a few options, and click go.

Volguus
Mar 3, 2009

PierreTheMime posted:

Now that I've gotten the backend working for an export/import utility, I want to work out a little GUI to avoid frightening people with command line or calling it from an object inside the tool itself. What would people's preferred GUI method for basic applications? I'm already starting in with Swing and getting "okay" results but I didn't want to dig in too far if there's a consensus there's a better option.

I basically just need it to populate a list and allow the user to highlight what they want, check a few options, and click go.

Swing is fine. A bit old and not really developed anymore (Oracle is dumping this entire Java thing it seems, so is not the only one), but there's nothing wrong with Swing. And it works.
JavaFX is the new UI framework, a bit flashier and prettier i guess. Swing is bundled with the JVM since 1.2. JavaFX is bundled with the JVM since 1.7.xx where xx is something like 40 something (if i remember correctly). Getting your feet wet with Swing then trying JavaFX at a later point is a viable strategy in my opinion.

GrundlePunch
Mar 23, 2016
I'm working on a side/personal project which accesses public US state information. Although each state largely provides the same information/data elements each agency has implemented their own web service with different protocols, content types, formatting etc. To that end I'm taking a crack at writing an application that accesses reporting by calling public web services in a way that's hidden to the user.

To my question: I have an implementation for one state that generates a URL in a particular state's format and can subsequently be called to return a report based on, location of interest, time frame, and nature of the report. Because the service has many optional parameters I copied a builder pattern. Having played with my (simplified) class below is there a good alternative to the number of ternary operators and the excessive null checking?

code:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

class Call {

	// Formatted API Call String
	private final String apiCall;

	// Call parameters
	private static final String API_URL = "http://url.com";
	private static final String API_VERSION = "1";
	private static final String API_VERSION_PARAMETER = "&version=";
	private static final String REPORT_NAME_PARAMETER ="?queryname=";
	private static final String START_DATE_TIME_PARAMETER = "&startdatetime=";
	private static final String END_DATE_TIME_PARAMETER = "&enddatetime=";
	private static final String LOCATION_ID_PARAMETER = "&locationid=";

	// Call parameter values
	private final String reportName;
	private final Calendar startDateTime;
	private final Calendar endDateTime;
	private final String formattedStartDateTime;
	private final String formattedEndDateTime;
	private final String locationId;

	public static class Builder {

		private DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH':'mm");

		private String apiCall;

		// Required parameters
		private String apiURL;
		private String apiVersion;
		private String apiVersionParameter;
		private String reportName;

		// Optional or report-specific parameters
		private Calendar startDateTime;
		private Calendar endDateTime;
		private String formattedStartDateTime;
		private String formattedEndDateTime;
		private String locationId;

		// Key names for request parameters
		private String reportNameParameter;
		private String startDateTimeParameter;
		private String endDateTimeParameter;
		private String locationIdParameter;

		//Call methods against builder to populate optional query parameters
		public Builder reportName(String value) {
			reportName = value;
			return this;
		}

		public Builder startDateTime(Calendar value) {
			startDateTime = (Calendar) value.clone();
			return this;
		}

		public Builder endDateTime(Calendar value) {
			endDateTime = (Calendar) value.clone();
			return this;
		}

		public Builder locationId(String value) {
			nodeName = value;
			return this;
		}

		public Call build() {

			//Check against presence of query values and appropriately instantiate parameter names
			reportNameParameter = reportName != null ? REPORT_NAME_PARAMETER : null;
			startDateTimeParameter = startDateTime != null ? START_DATE_TIME_PARAMETER : null;
			endDateTimeParameter = endDateTime != null ? END_DATE_TIME_PARAMETER : null;
			nodeNameParameter = nodeName != null ? LOCATION_ID_PARAMETER : null;
			formattedStartDateTime = startDateTime != null ? dateFormat.format(startDateTime.getTime()) + "-0000" : null;
			formattedEndDateTime = endDateTime != null ? dateFormat.format(endDateTime.getTime()) + "-0000" : null;

			apiCall = API_URL
					+ (reportNameParameter != null ? reportNameParameter : "")
					+ (reportName != null ? reportName : "")
					+ (startDateTimeParameter != null ? startDateTimeParameter : "")
					+ (formattedStartDateTime != null ? formattedStartDateTime : "")
					+ (endDateTimeParameter != null ? endDateTimeParameter : "")
					+ (formattedEndDateTime != null ? formattedEndDateTime : "")
					+ API_VERSION_PARAMETER
					+ API_VERSION
					+ (locationIdParameter != null ? locationIdParameter : "")
					+ (locationId != null ? locationId : "");

			return new Call(this);
		}

	}

	private Call(Builder builder) {
		reportName = builder.reportName;
		startDateTime = builder.startDateTime;
		formattedStartDateTime = builder.formattedStartDateTime;
		endDateTime = builder.endDateTime;
		formattedEndDateTime = builder.formattedEndDateTime;
		locationId = builder.locationId;

		apiCall = builder.apiCall;
	}

	public String toString() {
		return apiCall;
	}


	//Rest ommitted

}

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope
Maybe put all the parameters into a collection and then iterate over it?

Actually, there probably is some library that does this. This sounds like a common problem.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

My first instinct is to stick all that stuff in a map (a LinkedHashMap if you care about the ordering) of parameter names to values. That way you set the parameter if you have it, and when you come to build the query you can just iterate over the whole thing, and skip anything with a null value

Java code:
String value;
for (Map.Entry<String, String> param : allParams.entrySet()) {
	value = param.getValue();
	if (value != null) {
		query += param.getKey() + value;
	}
}
I'm guessing you need some kind of separator in there, and a StringBuilder might be better for putting it together, but you get the idea

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

PierreTheMime posted:

Now that I've gotten the backend working for an export/import utility, I want to work out a little GUI to avoid frightening people with command line or calling it from an object inside the tool itself. What would people's preferred GUI method for basic applications? I'm already starting in with Swing and getting "okay" results but I didn't want to dig in too far if there's a consensus there's a better option.

I basically just need it to populate a list and allow the user to highlight what they want, check a few options, and click go.

Whatever you use, find a nice GUI WYSIWYG designer/editor, writing GUI code by hand is miserable.

Eclipse WindowBuilder is decent enough.

Adbot
ADBOT LOVES YOU

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

baka kaba posted:

Java code:
String value;
for (Map.Entry<String, String> param : allParams.entrySet()) {

It's 2016, use
Java code:
allParams.entrySet().forEach(entry -> {/*whatever*/})
:mad:

edit:
If the value can be null, but you want to filter them out
Java code:
allParams.entrySet().filter(entry -> entry.getValue() != null).forEach(entry -> {/*whatever*/})

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply