What is the output of parse() in the class UriParserImplementation supposed to be?

I’m also a bit late with the parser, but I’ll try to understand the basics.

In the class UriParserImplementation, the method parse() receives the String uri as input and produces an output of type Uri, i.e. a Uri instance?

Suppose the input is the string uri = “https://somestuff”. What should be the output of parse()?

We have the grammar rule URI = scheme “:” hierarchical [ “?” query ]. So I presume that I should use Regex to split the string into scheme, hierarchical and query. But then how do I return this as something of type Uri? (Or what does type Uri actually mean?)

Edit 1: Do we call the methods from the UriImplementation class here, i.e. getScheme(), getQuery(),…? These methods return something of type String, so I’m still not sure how we convert this into something of type Uri.

In the class UriParserImplementation, the method parse() receives the String uri as input and produces an output of type Uri, i.e. a Uri instance?

The method parse does not take any explicit parameters, but it has the implicit this parameter, which can be used to access the fields of the UriParser object that parse was called upon.

Suppose the input is the string uri = “https://somestuff”. What should be the output of parse()?

Again, there is no input to parse. You would call parse on an instance of a class implementing the interface UriParser. Using the factory this would look as follows:

Uri uri = UriParserFactory.create("https://somestuff").parse();

The following should then hold:

uri.getScheme == "https"
uri.getUserInfo == null
uri.getHost instanceof IPv4 == false
uri.getHost.toString() == ""
uri.getPath == ""
uri.getQuery == null

Note that this does not tell you anything of how any implementation of Uri looks internally.

We have the grammar rule URI = scheme “:” hierarchical [ “?” query ]. So I presume that I should use Regex to split the string into scheme, hierarchical and query. But then how do I return this as something of type Uri? (Or what does type Uri actually mean?)

Regex is the fastest way to solve this project. (but not necessarily the best) In order to get the stuff you matched it is a good idea to use groups, you can google for more info on them. In order to turn the stuff you parsed into a Uri you need to call a constructor for your implementation of the interface Uri and pass it the relevant information.

Edit 1: Do we call the methods from the UriImplementation class here, i.e. getScheme(), getQuery(),…? These methods return something of type String, so I’m still not sure how we convert this into something of type Uri.

While I can not tell you the intent of the tutors and teaching assistants it seems to me that there is a clear separation of concerns in how the classes are designed:

  1. Uri is merely a container for the information that has been parsed.
  2. UriParser is where the actual parsing happens.
  3. UriParserFactory has nothing interesting going on in it. You create an instance of your implementation of UriParser and return it. No parsing should happen here, it is not the concern of the factory to replicate behaviour of the class it produces.
1 Like

You return an instance of type Uri. Since Uri is an interface, you need to create a sub-class of it (or maybe we have already done that for you). This is your class UriImplementation. Now, I suggest that this class should be a pure “data carrier” without any real functionality, and that all relevant parsing happens in the parse() method, before that object is constructed.

You need to ensure that you write the class such that (in your example), if someone (i.e. your/our tests) calls getScheme() on that instance of Uri, that method returns "https". If someone calls getHost(), you return "somestuff", and so on, consistent with this.

No. You implement these methods, since they do not yet exists (you know their name and type, and what they are supposed to do, but that’s it).

What I understand now is the following: parse() should return an instance of Uri. I can create a Uri instance by using the class UriImplementation (since it implements the interface Uri). So I presume that would look as follows (within the parse() method)?

Uri uri_instance = new UriImplementation(uri);
Unfortunately, VS Code said there was an error, something like “this constructor doesn’t exist”, then I clicked on “quick fix” → “create a constructor”, but this is probably not desired since I want to use the existing class UriImplementation, i.e. I’d have to import uri.implementation.UriImplementation? I also couldn’t find a way yet to undo the quick fix that I applied.

Now, suppose the above works, i.e. I have successfully constructed a Uri instance/object.

So before constructing the object, I shall do the parsing. But what is actually meant by that? The methods like getScheme() etc. are implemented in UriImplementation and not here in UriParserImplementation, right?

Yes, they are implemented there. That does not mean that they need to do significant calculation. In fact, they can (and should) just return a private field that you add to your UriImplementation class (i.e. work like a getter for some value you computed previously – hence the name).

Well, yes, unless you add that constructor yourself, it does not exist. The question you have to ask yourself is: What constructor do I want here? Does it make sense to have a constructor that just takes a single string, when the UriImplementation has getters for five different values? The answer is “probably not”.

Well, you got a single string. This string might follow the grammar, or not. Parsing means

  1. figuring out whether it does and
  2. while doing so, extracting the interesting parts, i.e. splitting the URI up into its constituent parts (scheme, host, path, …)

So you should have these five different parts neatly extracted at the end of “parsing”, and only then construct your UriImplementation using these five values. That is, unless you return null; beforehand because the input was not a valid URI.

It’s not, but it’s also not that wrong…

Well, yes, but your IDE should do that to you. Either way, it has nothing to do with a not matching constructor.

The quick fix (likely) added a constructor to the UriParserImplementation class. Remove it?

Alternatively, git diff should show you all the changes since the last commit. Perhaps you can spot where VSCode made changes?

1 Like