16 Commits
5 changed files with 200 additions and 158 deletions
+30 -55
View File
@@ -121,64 +121,40 @@ Understanding: You must be able to explain your implementation
## Bonus Tasks ✒️
1. Fetch and display movie information using movie ID
In this section, you must implement the ability to search for a movie by its ID. The user enters an ID, and the program displays complete movie details.
Implement movie search by ID. User enters an ID, program displays complete movie details.
Movie Class Fields (already defined):
### ⚠️ First: Add Missing Fields to Movie Class
The API returns more data than your current class supports. Add these fields:
- `actors`, `awards`, `director`, `imdb_id`, `imdb_votes`, `metascore`, `plot`, `rated`, `released`, `runtime`, `type`, `writer`
- id (Long) - Movie identifier
### Implementation Steps:
- title (String) - Movie title
1. **Complete `getMovieById(movieId)`**
- Build request to: `https://api.meshcomp.ir/api/v1/movies/{movieId}`
- If status 200 → return JSON body, else → return null
- year (String) - Release year
- genres (List<Genre>) - List of genres
- images (String) - Poster image URL
- country (String) - Production country
- imdbRating (String) - IMDB rating
Implementation Steps:
- Build and Send Request (getMovieById method):
- Create HTTP request to: https://api.meshcomp.ir/api/v1/movies/{movieId}
- Replace {movieId} with the ID from user
- Send request and get response
- Handle Response (getMovieById method):
- If status code is 200, return JSON body
- Otherwise, print error and return null
- Parse JSON and Create Movie Object (displayMovieDetails method):
- Parse JSON response to JsonObject
- Extract all fields: id, title, year, poster, country, imdb_rating
- Parse "genres" array and convert each to Genre object
- Create a Movie object with all extracted data
- Display Results (displayMovieDetails method):
- Print all movie details in a clean format
2. Advanced search (title, genre, year, rating, etc.)
3. Sorting options for movies
4. Save/load favorite movies to/from a file
5. Improved console menu design
6. GUI version using JavaFX
2. **Complete `displayMovieDetails(movieId)`**
- Call `getMovieById()` → check for null
- Use Gson to parse JSON to Movie object (after adding fields above)
- Print formatted output (see example below)
### Example Output:
```
=======================================================================
THE SHAWSHANK REDEMPTION (1994)
=======================================================================
Rating: 9.3/10 | Votes: 1,738,596
Director: Frank Darabont
Cast: Tim Robbins, Morgan Freeman, Bob Gunton, William Sadler
Genre: Crime, Drama
Runtime: 142 min | Rated: R
Country: USA | Released: 14 Oct 1994
Plot: Two imprisoned men bond over a number of years, finding
solace and eventual redemption through acts of common decency.
Awards: Nominated for 7 Oscars. Another 19 wins & 30 nominations.
=======================================================================
```
---
## References 📚
@@ -201,5 +177,4 @@ Jackson Tutorial:
---
## Submission ⌛
Deadline: May 1st (11 Ordibehesht)
Deadline: May 1st (11 Ordibehesht)
+34 -23
View File
@@ -51,45 +51,56 @@ public class Rational {
return r1.add(r2);
}
// TODO: Instance method - this - other
// Formula: a/b - c/d = (a*d - c*b) / (b*d)
// COMPLETED - Instance method - this - other
public Rational subtract(Rational other) {
// YOUR CODE HERE
return null; // Remove this line when implemented
int newNumerator = (this.numerator * other.denominator - other.numerator * this.denominator);
int newDenominator = this.denominator * other.denominator;
Rational result = new Rational(newNumerator, newDenominator);
result.simplify();
return result;
}
// TODO: Static method - r1 - r2
// COMPLETED - Static method - r1 - r2
public static Rational subtract(Rational r1, Rational r2) {
// YOUR CODE HERE
return null; // Remove this line when implemented
return r1.subtract(r2);
}
// TODO: Instance method - this * other
// Formula: (a/b) * (c/d) = (a*c) / (b*d)
// COMPLETED - Instance method - this * other
public Rational multiply(Rational other) {
// YOUR CODE HERE
return null; // Remove this line when implemented
int newNumerator = this.numerator * other.numerator;
int newDenominator = this.denominator * other.denominator;
Rational result = new Rational(newNumerator, newDenominator);
result.simplify();
return result;
}
// TODO: Static method - r1 * r2
// COMPLETED - Static method - r1 * r2
public static Rational multiply(Rational r1, Rational r2) {
// YOUR CODE HERE
return null; // Remove this line when implemented
return r1.multiply(r2);
}
// TODO: Instance method - this / other
// Formula: (a/b) ÷ (c/d) = (a*d) / (b*c)
// COMPLETED - Instance method - this / other
public Rational divide(Rational other) {
// YOUR CODE HERE
// HINT: Division is multiplication by reciprocal
// Don't forget to check if other.numerator is zero!
return null; // Remove this line when implemented
if (other.numerator == 0) {
throw new ArithmeticException("Caught division by zero");
}
int newNumerator = this.numerator * other.denominator;
int newDenominator = this.denominator * other.numerator;
Rational result = new Rational(newNumerator, newDenominator);
result.simplify();
return result;
}
// TODO: Static method - r1 / r2
// COMPLETED - Static method - r1 / r2
public static Rational divide(Rational r1, Rational r2) {
// YOUR CODE HERE
return null; // Remove this line when implemented
return r1.divide(r2);
}
// PROVIDED - String representation
+5 -3
View File
@@ -21,15 +21,17 @@ public class Main {
break;
case 2:
// TODO: Get genre ID and page from user, then call movieService.displayMoviesByGenre()
Long genreId = getLongInput("Please set your desired genre id: ");
Long page = getLongInput("Please set the number of the page: ");
movieService.displayMoviesByGenre(genreId, page);
break;
case 3:
// TODO (BONUS): Get movie ID from user, then call movieService.displayMovieDetails()
Long movieId = getLongInput("Please set the movie id: ");
movieService.displayMovieDetails(movieId);
break;
case 0:
+88 -10
View File
@@ -1,24 +1,102 @@
package movie.apis;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;
/**
* Model class representing a movie
* Fields: id, title, genres, images
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Movie {
private Long id;
private String title;
private List<Genre> genres;
private String images;
private List<String> genres;
private List<String> images;
private String year;
private String imdbRating;
private String released;
private String imdb_id;
private String imdb_votes;
private String imdb_rating;
private String meta_score;
private String country;
private String actors;
private String director;
private String writer;
private String awards;
private String plot;
private String rated;
private String runtime;
private String type;
// TODO: Create a constructor with all fields
public Movie(Long id, String title, List<String> genres, List<String> images, String year, String released, String imdb_id,
String imdb_votes, String imdb_rating, String country, String actors, String director, String writer, String awards,
String plot, String rated, String runtime, String type) {
// TODO: Create a simple constructor with id and title only
this(id, title, genres, images, year, imdb_rating, country);
this.released = released;
this.imdb_id = imdb_id;
this.imdb_votes = imdb_votes;
this.actors = actors;
this.director = director;
this.writer = writer;
this.awards = awards;
this.plot = plot;
this.rated = rated;
this.runtime = runtime;
this.type = type;
}
// TODO: Create getters and setters for all fields
public Movie(Long id, String title, List<String> genres, List<String> images, String year, String imdb_rating, String country) {
this(id, title);
this.genres = genres;
this.images = images;
this.year = year;
this.imdb_rating = imdb_rating;
this.country = country;
}
public Movie(Long id, String title) {
this.id = id;
this.title = title;
}
public Movie() {}
public void setId(Long id) {this.id = id;}
public void setTitle(String title) {this.title = title;}
public void setGenres(List<String> genres) {this.genres = genres;}
public void setImages(List<String> images) {this.images = images;}
public void setYear(String year) {this.year = year;}
public void setCountry(String country) {this.country = country;}
public void setImdb_rating(String imdb_rating) {this.imdb_rating = imdb_rating;}
public void setActors(String actors) {this.actors = actors;}
public void setAwards(String awards) {this.awards = awards;}
public void setDirector(String director) {this.director = director;}
public void setImdb_id(String imdb_id) {this.imdb_id = imdb_id;}
public void setImdb_votes(String imdb_votes) {this.imdb_votes = imdb_votes;}
public void setMeta_score(String meta_score) {this.meta_score = meta_score;}
public void setPlot(String plot) {this.plot = plot;}
public void setRated(String rated) {this.rated = rated;}
public void setReleased(String released) {this.released = released;}
public void setRuntime(String runtime) {this.runtime = runtime;}
public void setType(String type) {this.type = type;}
public void setWriter(String writer) {this.writer = writer;}
public Long getId() {return id;}
public String getTitle() {return title;}
public List<String> getGenres() {return genres;}
public List<String> getImages() {return images;}
public String getYear() {return year;}
public String getCountry() {return country;}
public String getImdb_rating() {return imdb_rating;}
public String getActors() {return actors;}
public String getImdb_id() {return imdb_id;}
public String getDirector() {return director;}
public String getImdb_votes() {return imdb_votes;}
public String getAwards() {return awards;}
public String getMeta_score() {return meta_score;}
public String getPlot() {return plot;}
public String getRated() {return rated;}
public String getReleased() {return released;}
public String getRuntime() {return runtime;}
public String getType() {return type;}
public String getWriter() {return writer;}
}
+43 -67
View File
@@ -1,5 +1,7 @@
package movie.apis;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
@@ -87,43 +89,38 @@ public class MovieService {
}
}
/**
* TODO 1: Display movies for a specific genre and page
*
* JSON format: { "movies": [ { "id": 1, "title": "Movie", "year": "1994" } ], "total": 177, "total_pages": 18 }
*
* Steps:
* - Call getMoviesByGenreList(genreId, page) to get JSON
* - Parse JSON to JsonObject
* - Get "movies" array (NOT "data")
* - Loop through array and print: "ID: {id} | {title} ({year})"
* - Also print total and total_pages
*
* PUT ALL PARSING CODE INSIDE try-catch
*/
public void displayMoviesByGenre(Long genreId, Long page) {
// TODO: Write your code here
// All parsing code must be inside try-catch
try {
// Your code here
String jsonData = getMoviesByGenreList(genreId, page);
} catch (Exception e) {
try {
JsonObject jsonObject = JsonParser.parseString(jsonData).getAsJsonObject();
String moviesJson = jsonObject.get("movies").toString();
ObjectMapper mapper = new ObjectMapper();
List<Movie> movies = mapper.readValue(
moviesJson,
new TypeReference<List<Movie>>() {}
);
for (Movie movie : movies) {
System.out.println("ID: " + movie.getId() + " | " + movie.getTitle() + " ( " + movie.getYear() + ")");
}
System.out.println("total: " + movies.size() + " | page: " + page + " | total pages: " + movies.size()/10);
}
catch (Exception e) {
System.err.println("ERROR: " + e.getMessage());
}
}
/**
* BONUS: Fetch movie details from API using movie ID
* URL format: https://api.meshcomp.ir/api/v1/movies/{movieId}
*/
private String getMovieById(Long movieId) {
try {
// TODO: Complete this method
// String url = MOVIE_BY_ID_URL + movieId;
// HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).build();
// HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// if (response.statusCode() == 200) return response.body();
String url = MOVIE_BY_ID_URL + movieId;
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) return response.body();
return null;
} catch (Exception e) {
@@ -131,54 +128,33 @@ public class MovieService {
}
return null;
}
/**
* BONUS TODO: Display complete movie details for a given movie ID
*
* Expected JSON format from getMovieById():
* {
* "id": 1,
* "title": "The Shawshank Redemption",
* "year": "1994",
* "genres": ["Crime", "Drama"],
* "poster": "https://moviesapi.ir/images/tt0111161_poster.jpg",
* "country": "USA",
* "imdb_rating": "9.3"
* }
*
* INSTRUCTIONS:
* 1. Call getMovieById(movieId) to get the JSON response
* 2. Check if response is null (if yes, print error and return)
* 3. Parse the JSON string to JsonObject (inside try-catch)
* 4. Extract all fields: id, title, year, genres array, poster, country, imdb_rating
* 5. Convert genres array to comma-separated string
* 6. Print all movie details in a readable format
*
* PUT ALL PARSING CODE INSIDE THE EXISTING try-catch
*
* @param movieId The ID of the movie to display
*/
public void displayMovieDetails(Long movieId) {
// Step 1: Get JSON response from API
String jsonResponse = getMovieById(movieId);
// Step 2: Check if we got valid data
if (jsonResponse == null) {
System.out.println("Failed to get movie details for ID: " + movieId);
return;
}
// Step 3-6: Parse JSON and display details (PUT YOUR CODE INSIDE try-catch)
try {
// TODO: Parse jsonResponse to JsonObject
// TODO: Extract id, title, year, genres array, poster, country, imdb_rating
// TODO: Convert genres array to a readable string
// TODO: Print all movie details
// HINT: Use JsonParser.parseString(jsonResponse).getAsJsonObject()
// HINT: Use getAsJsonArray("genres") to get genres
// HINT: For each genre, use getAsString()
JsonObject jsonObject = JsonParser.parseString(jsonResponse).getAsJsonObject();
// Your code here:
Gson gson = new Gson();
Movie movie = gson.fromJson(jsonObject, Movie.class);
System.out.println("=======================================================================");
System.out.println(movie.getTitle() + " ( " + movie.getYear() + ")");
System.out.println("=======================================================================");
System.out.println("Rating: " + movie.getImdb_rating() + "/10 | Votes: " + movie.getImdb_votes());
System.out.println("Director: " + movie.getDirector());
System.out.println("Cast: " + movie.getActors());
System.out.println("Genre: " + movie.getGenres());
System.out.println("Runtime: " + movie.getRuntime() + " min | Rated: " + movie.getRated());
System.out.println("Country: " + movie.getCountry() + " | Released: " + movie.getReleased());
System.out.println("plot: " + movie.getPlot());
System.out.println("Awards: " + movie.getAwards());
System.out.println("=======================================================================");
} catch (Exception e) {