develop #1
+38
@@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
Generated
+3
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+14
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" project-jdk-name="25" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,2 +1,205 @@
|
||||
# Second-Assignment-Movie-App
|
||||
## Third Assignment: Movie Explorer 🎬 + Rational Calculator 🧮
|
||||
---
|
||||
|
||||
Welcome to Your Third Assignment in the Advanced Programming Course!
|
||||
|
||||
This assignment consists of two separate parts. You must complete both parts.
|
||||
|
||||
---
|
||||
|
||||
## Part 1: Rational Class (Rational Numbers)
|
||||
In this part, you will implement a Rational class that supports basic mathematical operations.
|
||||
|
||||
A `RationalTest` class is provided.
|
||||
+You can run it to verify that your implementation works correctly.
|
||||
+Use it to test your logic before submitting.
|
||||
|
||||
Tasks:
|
||||
Define fields for numerator and denominator
|
||||
|
||||
Implement addition, subtraction, multiplication, and division as instance methods
|
||||
|
||||
Implement addition, subtraction, multiplication, and division as static methods
|
||||
|
||||
Note: Detailed TODO comments are provided inside Rational.java.
|
||||
Do NOT modify the constructor, simplify logic, or completed methods.
|
||||
Only complete the TODO methods.
|
||||
|
||||
---
|
||||
## Part 2: Movie Explorer 🎬 (Using API)
|
||||
In this part, you will develop a Java application that fetches movie data from an API and allows users to browse and search movies.
|
||||
|
||||
### Files Provided
|
||||
- `Movie.java`
|
||||
- `Genre.java`
|
||||
- `MovieService.java`
|
||||
- `Main.java`
|
||||
|
||||
The `Genre` class is already implemented as a sample.
|
||||
You must design and implement the `Movie` class yourself (fields, constructors, getters, setters, toString if needed).
|
||||
|
||||
We have already implemented two methods that call the API and return the raw JSON response as a `String`:
|
||||
|
||||
- `getGenresList()` → calls the API and returns the list of genres in JSON format.
|
||||
- `getMoviesByGenreList(Long genreId, Long page)` → calls the API and returns the list of movies for a specific genre and page in JSON format.
|
||||
|
||||
Do NOT modify:
|
||||
API URLs
|
||||
`getGenresList()`
|
||||
`getMoviesByGenreList()`
|
||||
|
||||
Only complete the TODO methods.
|
||||
|
||||
### Your Tasks
|
||||
|
||||
1. Complete the `Movie` class (fields, constructor, getters, and setters).
|
||||
|
||||
2. Write a method that receives the JSON string returned by `getMoviesByGenreList()` and converts it into a `List<Movie>`.
|
||||
|
||||
3. Write another method that displays the list of movies (for the selected genre) in a clean and readable format.
|
||||
|
||||
4. Implement a console menu in `Main` that allows the user to:
|
||||
- View the list of genres
|
||||
- Select a genre
|
||||
- View movies for the selected genre (with pagination)
|
||||
After completing `MovieService`, you must also complete the `Main` class
|
||||
so the menu works correctly.
|
||||
### Note
|
||||
|
||||
To understand what fields should exist in the `Genre` and `Movie` classes, it is recommended that you first call the two API methods once and inspect the raw JSON response. This will help you determine the exact structure of the data and define the appropriate class fields.
|
||||
We implemented JSON parsing using **Gson** in the project.
|
||||
However, the **Jackson dependency is also included**.
|
||||
If you prefer, you are allowed to use Jackson instead of Gson.
|
||||
|
||||
---
|
||||
## Objectives ✏️
|
||||
By completing this assignment, you will:
|
||||
|
||||
Reinforce OOP concepts: class design, constructors, encapsulation, collections
|
||||
|
||||
Practice instance methods vs. static methods
|
||||
|
||||
Work with JSON parsing and REST APIs
|
||||
|
||||
Design a simple console-based menu
|
||||
|
||||
Improve Git workflow and project management
|
||||
|
||||
----
|
||||
## Prerequisites ✅
|
||||
Git
|
||||
|
||||
Java (version 23 or 25)
|
||||
|
||||
Maven as a package manager
|
||||
|
||||
---
|
||||
## Tasks Summary 📝
|
||||
Fork the repository and clone it locally
|
||||
|
||||
Create and switch to a development branch
|
||||
|
||||
Complete Part 1 (Rational.java) following the TODO comments
|
||||
|
||||
Complete Part 2 (Movie.java, Genre.java, MovieService.java, Main.java) following the TODO comments
|
||||
|
||||
Ensure the code compiles and runs correctly
|
||||
|
||||
Commit and push regularly
|
||||
|
||||
Submit a pull request from development to main
|
||||
|
||||
---
|
||||
## Evaluation Criteria ⚖️
|
||||
Functionality: Code compiles and runs without errors; all features work correctly
|
||||
|
||||
Code Quality: Clean, readable, well-structured code with proper naming
|
||||
|
||||
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.
|
||||
|
||||
Movie Class Fields (already defined):
|
||||
|
||||
- id (Long) - Movie identifier
|
||||
|
||||
- title (String) - Movie title
|
||||
|
||||
- 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
|
||||
|
||||
---
|
||||
## References 📚
|
||||
|
||||
API (Replace placeholders with numbers):
|
||||
- genres: https://api.meshcomp.ir/api/v1/genres
|
||||
- movies: https://api.meshcomp.ir/api/v1/movies
|
||||
- movies (specifying the page): https://api.meshcomp.ir/api/v1/movies?page={pageId}
|
||||
- movies by genres: https://api.meshcomp.ir/api/v1/genres/{genreId}/movies?page={pageId}
|
||||
- details of a specific movie: https://api.meshcomp.ir/api/v1/movies/{movieId}
|
||||
|
||||
Video Tutorials (watch before starting the assignment):
|
||||
[link](https://drive.meshcomp.ir/d/a29a5f6ea6484834bcf0/)
|
||||
|
||||
Gson Tutorial:
|
||||
[`Gson` Reading and Parsing Data from a JSONObject](https://drive.meshcomp.ir/f/e8dea01f31b24cbca152/)
|
||||
|
||||
|
||||
Jackson Tutorial:
|
||||
[`Jackson` Parsing Json in Java Tutorial - Part 1 Jackson and Simple Objects](https://drive.meshcomp.ir/f/005d8f8fc19a44f4927b/)
|
||||
|
||||
---
|
||||
## Submission ⌛
|
||||
Deadline: May 1st (11 Ordibehesht)
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.to</groupId>
|
||||
<artifactId>HW03</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- GSON: Google JSON parsing library -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson: Another JSON parsing library -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.17.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,108 @@
|
||||
package Rational;
|
||||
|
||||
public class Rational {
|
||||
private int numerator;
|
||||
private int denominator;
|
||||
|
||||
// Constructor
|
||||
public Rational(int numerator, int denominator) {
|
||||
if (denominator == 0) {
|
||||
throw new IllegalArgumentException("Denominator cannot be zero");
|
||||
}
|
||||
this.numerator = numerator;
|
||||
this.denominator = denominator;
|
||||
simplify();
|
||||
}
|
||||
|
||||
// GCD helper for simplification
|
||||
private int gcd(int a, int b) {
|
||||
a = Math.abs(a);
|
||||
b = Math.abs(b);
|
||||
while (b != 0) {
|
||||
int temp = b;
|
||||
b = a % b;
|
||||
a = temp;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// Simplify the fraction
|
||||
private void simplify() {
|
||||
int gcd = gcd(numerator, denominator);
|
||||
numerator /= gcd;
|
||||
denominator /= gcd;
|
||||
|
||||
// Keep denominator positive
|
||||
if (denominator < 0) {
|
||||
numerator = -numerator;
|
||||
denominator = -denominator;
|
||||
}
|
||||
}
|
||||
|
||||
// COMPLETED - Instance method: this + other
|
||||
public Rational add(Rational other) {
|
||||
int newNumerator = this.numerator * other.denominator + other.numerator * this.denominator;
|
||||
int newDenominator = this.denominator * other.denominator;
|
||||
return new Rational(newNumerator, newDenominator);
|
||||
}
|
||||
|
||||
// COMPLETED - Static method: r1 + r2
|
||||
public static Rational add(Rational r1, Rational r2) {
|
||||
return r1.add(r2);
|
||||
}
|
||||
|
||||
// TODO: Instance method - this - other
|
||||
// Formula: a/b - c/d = (a*d - c*b) / (b*d)
|
||||
public Rational subtract(Rational other) {
|
||||
// YOUR CODE HERE
|
||||
return null; // Remove this line when implemented
|
||||
}
|
||||
|
||||
// TODO: Static method - r1 - r2
|
||||
public static Rational subtract(Rational r1, Rational r2) {
|
||||
// YOUR CODE HERE
|
||||
return null; // Remove this line when implemented
|
||||
}
|
||||
|
||||
// TODO: Instance method - this * other
|
||||
// Formula: (a/b) * (c/d) = (a*c) / (b*d)
|
||||
public Rational multiply(Rational other) {
|
||||
// YOUR CODE HERE
|
||||
return null; // Remove this line when implemented
|
||||
}
|
||||
|
||||
// TODO: Static method - r1 * r2
|
||||
public static Rational multiply(Rational r1, Rational r2) {
|
||||
// YOUR CODE HERE
|
||||
return null; // Remove this line when implemented
|
||||
}
|
||||
|
||||
// TODO: Instance method - this / other
|
||||
// Formula: (a/b) ÷ (c/d) = (a*d) / (b*c)
|
||||
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
|
||||
}
|
||||
|
||||
// TODO: Static method - r1 / r2
|
||||
public static Rational divide(Rational r1, Rational r2) {
|
||||
// YOUR CODE HERE
|
||||
return null; // Remove this line when implemented
|
||||
}
|
||||
|
||||
// PROVIDED - String representation
|
||||
@Override
|
||||
public String toString() {
|
||||
if (denominator == 1) {
|
||||
return numerator + "";
|
||||
}
|
||||
return numerator + "/" + denominator;
|
||||
}
|
||||
|
||||
// PROVIDED - Decimal value
|
||||
public double toDouble() {
|
||||
return (double) numerator / denominator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package Rational;
|
||||
|
||||
public class RationalTest {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== Testing Rational Operations ===\n");
|
||||
|
||||
// Create some rational numbers
|
||||
Rational r1 = new Rational(1, 2); // 1/2
|
||||
Rational r2 = new Rational(1, 3); // 1/3
|
||||
Rational r3 = new Rational(3, 4); // 3/4
|
||||
Rational r4 = new Rational(2, 5); // 2/5
|
||||
Rational r5 = new Rational(5, 1); // 5 (integer)
|
||||
|
||||
System.out.println("Created rational numbers:");
|
||||
System.out.println("r1 = " + r1);
|
||||
System.out.println("r2 = " + r2);
|
||||
System.out.println("r3 = " + r3);
|
||||
System.out.println("r4 = " + r4);
|
||||
System.out.println("r5 = " + r5);
|
||||
System.out.println();
|
||||
|
||||
// Test ADDITION
|
||||
System.out.println("=== ADDITION ===");
|
||||
System.out.println("Instance method - r1 + r2 = " + r1.add(r2));
|
||||
System.out.println("Static method - Rational.add(r1, r2) = " + Rational.add(r1, r2));
|
||||
System.out.println("Expected: 1/2 + 1/3 = 5/6");
|
||||
System.out.println("Decimal: " + r1.add(r2).toDouble());
|
||||
System.out.println();
|
||||
|
||||
// Test SUBTRACTION
|
||||
System.out.println("=== SUBTRACTION ===");
|
||||
System.out.println("Instance method - r1 - r2 = " + r1.subtract(r2));
|
||||
System.out.println("Static method - Rational.subtract(r1, r2) = " + Rational.subtract(r1, r2));
|
||||
System.out.println("Expected: 1/2 - 1/3 = 1/6");
|
||||
System.out.println("Decimal: " + r1.subtract(r2).toDouble());
|
||||
System.out.println();
|
||||
|
||||
// Test MULTIPLICATION
|
||||
System.out.println("=== MULTIPLICATION ===");
|
||||
System.out.println("Instance method - r1 * r3 = " + r1.multiply(r3));
|
||||
System.out.println("Static method - Rational.multiply(r1, r3) = " + Rational.multiply(r1, r3));
|
||||
System.out.println("Expected: 1/2 * 3/4 = 3/8");
|
||||
System.out.println("Decimal: " + r1.multiply(r3).toDouble());
|
||||
System.out.println();
|
||||
|
||||
// Test DIVISION
|
||||
System.out.println("=== DIVISION ===");
|
||||
System.out.println("Instance method - r1 ÷ r2 = " + r1.divide(r2));
|
||||
System.out.println("Static method - Rational.divide(r1, r2) = " + Rational.divide(r1, r2));
|
||||
System.out.println("Expected: 1/2 ÷ 1/3 = 3/2");
|
||||
System.out.println("Decimal: " + r1.divide(r2).toDouble());
|
||||
System.out.println();
|
||||
|
||||
// Test with negative numbers
|
||||
System.out.println("=== NEGATIVE NUMBERS ===");
|
||||
Rational neg1 = new Rational(-2, 3);
|
||||
Rational neg2 = new Rational(4, -5);
|
||||
System.out.println("neg1 = " + neg1); // Should show -2/3
|
||||
System.out.println("neg2 = " + neg2); // Should show -4/5
|
||||
System.out.println("neg1 + neg2 = " + neg1.add(neg2));
|
||||
System.out.println("-2/3 + -4/5 = (-10/15 + -12/15) = -22/15");
|
||||
System.out.println("neg1 * neg2 = " + neg1.multiply(neg2));
|
||||
System.out.println("(-2/3) * (-4/5) = 8/15");
|
||||
System.out.println();
|
||||
|
||||
// Test simplification
|
||||
System.out.println("=== SIMPLIFICATION ===");
|
||||
Rational r6 = new Rational(6, 8);
|
||||
Rational r7 = new Rational(10, 25);
|
||||
Rational r8 = new Rational(18, -24);
|
||||
System.out.println("6/8 simplified = " + r6);
|
||||
System.out.println("10/25 simplified = " + r7);
|
||||
System.out.println("18/-24 simplified = " + r8);
|
||||
System.out.println();
|
||||
|
||||
// Test chaining operations
|
||||
System.out.println("=== CHAINING OPERATIONS ===");
|
||||
Rational result = r1.add(r2).multiply(r3).divide(r4);
|
||||
System.out.println("((r1 + r2) * r3) ÷ r4 = " + result);
|
||||
System.out.println("((1/2 + 1/3) * 3/4) ÷ 2/5 = (5/6 * 3/4) ÷ 2/5 = (15/24) ÷ 2/5 = 15/24 * 5/2 = 75/48 = 25/16");
|
||||
System.out.println("Decimal: " + result.toDouble());
|
||||
System.out.println();
|
||||
|
||||
// Test integer handling
|
||||
System.out.println("=== INTEGER HANDLING ===");
|
||||
System.out.println("r5 = " + r5); // Should show 5, not 5/1
|
||||
System.out.println("r5 + r1 = " + r5.add(r1));
|
||||
System.out.println("5 + 1/2 = 11/2");
|
||||
System.out.println("r1 * r5 = " + r1.multiply(r5));
|
||||
System.out.println("1/2 * 5 = 5/2");
|
||||
System.out.println();
|
||||
|
||||
// Test exception handling
|
||||
System.out.println("=== EXCEPTION TEST ===");
|
||||
try {
|
||||
Rational invalid = new Rational(1, 0);
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.out.println("Caught exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
Rational zero = new Rational(0, 1);
|
||||
Rational divisionByZero = r1.divide(zero);
|
||||
} catch (ArithmeticException e) {
|
||||
System.out.println("Caught division by zero: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package movie.apis;
|
||||
|
||||
public class Genre {
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public Genre(Long id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Genre() {
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id + ". " + name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package movie.apis;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static final MovieService movieService = new MovieService();
|
||||
private static final Scanner scanner = new Scanner(System.in);
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("\n=== MOVIE API CLIENT ===\n");
|
||||
|
||||
boolean running = true;
|
||||
while (running) {
|
||||
displayMenu();
|
||||
int choice = getIntInput("Enter your choice: ");
|
||||
|
||||
switch (choice) {
|
||||
case 1:
|
||||
movieService.displayGenres();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// TODO: Get genre ID and page from user, then call movieService.displayMoviesByGenre()
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 3:
|
||||
// TODO (BONUS): Get movie ID from user, then call movieService.displayMovieDetails()
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case 0:
|
||||
running = false;
|
||||
System.out.println("Goodbye!");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
System.out.println("Invalid choice! Please enter 0-4");
|
||||
}
|
||||
|
||||
if (running) {
|
||||
System.out.println("\nPress Enter to continue...");
|
||||
scanner.nextLine();
|
||||
scanner.nextLine();
|
||||
}
|
||||
}
|
||||
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
private static void displayMenu() {
|
||||
System.out.println("\n================================");
|
||||
System.out.println(" MENU");
|
||||
System.out.println("================================");
|
||||
System.out.println("1. Get all genres");
|
||||
System.out.println("2. Get movies by genre ID");
|
||||
System.out.println("3. Get movie details by ID");
|
||||
System.out.println("0. Exit");
|
||||
System.out.println("================================");
|
||||
}
|
||||
|
||||
private static int getIntInput(String prompt) {
|
||||
System.out.print(prompt);
|
||||
while (!scanner.hasNextInt()) {
|
||||
System.out.print("Invalid input. " + prompt);
|
||||
scanner.next();
|
||||
}
|
||||
int input = scanner.nextInt();
|
||||
scanner.nextLine();
|
||||
return input;
|
||||
}
|
||||
|
||||
private static Long getLongInput(String prompt) {
|
||||
System.out.print(prompt);
|
||||
while (!scanner.hasNextLong()) {
|
||||
System.out.print("Invalid input. " + prompt);
|
||||
scanner.next();
|
||||
}
|
||||
Long input = scanner.nextLong();
|
||||
scanner.nextLine();
|
||||
return input;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package movie.apis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Model class representing a movie
|
||||
* Fields: id, title, genres, images
|
||||
*/
|
||||
public class Movie {
|
||||
|
||||
private Long id;
|
||||
private String title;
|
||||
private List<Genre> genres;
|
||||
private String images;
|
||||
private String year;
|
||||
private String imdbRating;
|
||||
private String country;
|
||||
|
||||
// TODO: Create a constructor with all fields
|
||||
|
||||
// TODO: Create a simple constructor with id and title only
|
||||
|
||||
// TODO: Create getters and setters for all fields
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package movie.apis;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MovieService {
|
||||
|
||||
private final static String GENRES_URL = "https://api.meshcomp.ir/api/v1/genres";
|
||||
private final static String MOVIE_BY_ID_URL = "https://api.meshcomp.ir/api/v1/movies/";
|
||||
private final static HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
private String getGenresList() {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(GENRES_URL))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if (response.statusCode() == 200) {
|
||||
System.out.println("Genres List received successfully");
|
||||
return response.body();
|
||||
} else {
|
||||
throw new IOException("HTTP error code: " + response.statusCode());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("!!Exception : " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getMoviesByGenreList(Long genreId, Long page) {
|
||||
try {
|
||||
String url = "https://api.meshcomp.ir/api/v1/genres/" + genreId + "/movies?page=" + page;
|
||||
|
||||
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();
|
||||
} else {
|
||||
System.out.println("HTTP error code: " + response.statusCode());
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("!!Exception : " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void displayGenres() {
|
||||
String jsonResponse = getGenresList();
|
||||
|
||||
if (jsonResponse == null) {
|
||||
System.out.println("Failed to get genres");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JsonObject rootObject = JsonParser.parseString(jsonResponse).getAsJsonObject();
|
||||
JsonArray genresArray = rootObject.getAsJsonArray("genres");
|
||||
Type genreListType = new TypeToken<ArrayList<Genre>>(){}.getType();
|
||||
Gson gson = new Gson();
|
||||
List<Genre> genres = gson.fromJson(genresArray, genreListType);
|
||||
|
||||
System.out.println("\nALL GENRES:");
|
||||
for (Genre genre : genres) {
|
||||
System.out.println(genre.getId() + ". " + genre.getName());
|
||||
}
|
||||
System.out.println();
|
||||
} catch (Exception e) {
|
||||
System.err.println("ERROR parsing genres: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
} 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();
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
System.out.println("!!Exception : " + e.getMessage());
|
||||
}
|
||||
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()
|
||||
|
||||
// Your code here:
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("ERROR parsing movie details: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user