0% found this document useful (0 votes)
1 views18 pages

Java Knowledge Book

The document is a comprehensive guide for Java developers focusing on building a Smart Job Tracker project. It covers essential topics such as JWT authentication, Spring Scheduler, JavaMail integration, JPA, DTO patterns, global exception handling, and analytics queries. Each chapter provides detailed explanations, code snippets, and best practices for implementing these concepts in a Java application.

Uploaded by

Dayama company
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views18 pages

Java Knowledge Book

The document is a comprehensive guide for Java developers focusing on building a Smart Job Tracker project. It covers essential topics such as JWT authentication, Spring Scheduler, JavaMail integration, JPA, DTO patterns, global exception handling, and analytics queries. Each chapter provides detailed explanations, code snippets, and best practices for implementing these concepts in a Java application.

Uploaded by

Dayama company
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

JAVA DEVELOPER KNOWLEDGE

BOOK
Everything You Need to Build the Smart Job Tracker Project

10 Chapters | JWT | Scheduling | JavaMail | JPA | DTOs | Testing

Exception Handling | Analytics Queries | Soft Delete | REST Design

Prepared for: Devansh Dayama — Java Developer Intern


TABLE OF CONTENTS

Ch 1 Spring Security + JWT Complete JWT implementation from scratch

Ch 2 Spring Scheduler Background jobs, @Scheduled, cron expressions

Ch 3 JavaMailSender SMTP config, HTML emails, Gmail App Password

Ch 4 Spring Data JPA Deep Dive Custom JPQL, entity annotations, relationships

Ch 5 DTO Pattern Why DTOs matter, mapping, Lombok @Builder

Ch 6 Global Exception Handling @ControllerAdvice, custom exceptions, error DTOs

Ch 7 Analytics Queries GROUP BY, COUNT, AVG, date functions in JPQL

Ch 8 Soft Delete Pattern @Where, @SQLDelete, data integrity

Ch 9 REST API Design HTTP methods, status codes, best practices

Ch 10 Unit Testing JUnit 5 + Mockito, service testing, mocking


CHAPTER 1

Spring Security + JWT Authentication

What is JWT?
JSON Web Token (JWT) is a compact token encoding a user's identity. It has three dot-separated parts:
Header (algorithm), Payload (user data + expiry), and Signature (cryptographic proof). At login the server
creates it; the client sends it on every request; the server verifies the signature — no database lookup
needed.

JWT Structure
eyJhbGciOiJIUzI1NiJ9 <- Header (base64 encoded)

.eyJzdWIiOiJ1c2VyQGdtYWlsLmNvbSIsImV4cCI6MTcwMDAwfQ

<- Payload: sub=email, exp=expiry timestamp

.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

<- Signature: HMAC-SHA256(header+payload, secret)

Maven Dependencies ([Link])


<!-- Spring Security -->

<dependency>

<groupId>[Link]</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

<!-- JJWT library -->

<dependency>

<groupId>[Link]</groupId>

<artifactId>jjwt-api</artifactId>

<version>0.12.3</version>

</dependency>

<dependency>

<groupId>[Link]</groupId>

<artifactId>jjwt-impl</artifactId>

<version>0.12.3</version>

</dependency>

<dependency>

<groupId>[Link]</groupId>

<artifactId>jjwt-jackson</artifactId>

<version>0.12.3</version>

</dependency>

[Link]
@Component

public class JwtTokenProvider {


@Value("${[Link]}") private String secret;

@Value("${[Link]}") private long expiration; // ms, e.g. 86400000 = 24h

public String generateToken(String username) {

return [Link]()

.subject(username)

.issuedAt(new Date())

.expiration(new Date([Link]() + expiration))

.signWith(getKey())

.compact();

public String extractUsername(String token) {

return [Link]().verifyWith(getKey()).build()

.parseSignedClaims(token).getPayload().getSubject();

public boolean validate(String token) {

try { [Link]().verifyWith(getKey()).build().parseSignedClaims(token); return


true; }

catch (Exception e) { return false; }

private SecretKey getKey() {

return [Link]([Link](secret));

[Link] (runs on every request)


@Component

public class JwtAuthFilter extends OncePerRequestFilter {

@Autowired private JwtTokenProvider jwt;

@Autowired private UserDetailsService uds;

@Override

protected void doFilterInternal(HttpServletRequest req,

HttpServletResponse res, FilterChain chain) throws IOException, ServletException {

String header = [Link]("Authorization");

if (header != null && [Link]("Bearer ")) {

String token = [Link](7);

if ([Link](token)) {

String username = [Link](token);

UserDetails ud = [Link](username);

var auth = new UsernamePasswordAuthenticationToken(

ud, null, [Link]());

[Link](new WebAuthenticationDetailsSource().buildDetails(req));
[Link]().setAuthentication(auth);

[Link](req, res);

[Link]
@Configuration @EnableWebSecurity

public class SecurityConfig {

@Autowired private JwtAuthFilter jwtFilter;

@Bean

public SecurityFilterChain chain(HttpSecurity http) throws Exception {

[Link](c -> [Link]())

.sessionManagement(s -> [Link](STATELESS))

.authorizeHttpRequests(a -> a

.requestMatchers("/api/auth/**").permitAll()

.anyRequest().authenticated())

.addFilterBefore(jwtFilter, [Link]);

return [Link]();

@Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(); }

KEY: The JwtAuthFilter intercepts every request before Spring's default auth. It reads the Bearer token,
validates it, extracts the username, loads the UserDetails, and sets authentication in SecurityContextHolder.
Controllers can then access the current user via [Link]().getAuthentication().
CHAPTER 2

Spring Scheduler and Cron Jobs


@Scheduled lets a method run automatically on a schedule. Spring manages a background thread pool.
You never call these methods manually — Spring triggers them at the right time. Enable it with
@EnableScheduling on your main class.

Cron Syntax: second minute hour dayOfMonth month dayOfWeek

Expression When It Runs

0 0 9 * * MON-FRI Every weekday at 9:00 AM

000*** Every day at midnight

0 0/30 * * * * Every 30 minutes

0091** First day of month at 9 AM

0 0 8,17 * * * 8 AM and 5 PM every day

[Link]
@Component

public class ReminderScheduler {

@Autowired private JobApplicationRepository repo;

@Autowired private EmailService email;

@Scheduled(cron = "0 0 9 * * MON-FRI")

public void sendReminders() {

LocalDateTime threshold = [Link]().minusDays(7);

List<JobApplication> stale =

[Link](threshold);

for (JobApplication app : stale) {

try {

[Link](

[Link]().getEmail(),

[Link](), [Link]());

[Link](true);

[Link](app);

} catch (Exception e) {

[Link]("Reminder failed: " + [Link]());

// Continue — don't let one failure stop all reminders

}
CHAPTER 3

JavaMailSender and Email Integration


[Link]
[Link]=[Link]

[Link]=587

[Link]=youremail@[Link]

[Link]=xxxx_xxxx_xxxx_xxxx # Gmail App Password (NOT login password)

[Link]=true

[Link]=true

# How to get Gmail App Password:

# Google Account -> Security -> 2-Step Verification -> App passwords -> Generate

[Link]
@Service

public class EmailService {

@Autowired private JavaMailSender mailer;

public void sendReminderEmail(String to, String position, String company) {

try {

MimeMessage msg = [Link]();

MimeMessageHelper h = new MimeMessageHelper(msg, true);

[Link](to);

[Link]("noreply@[Link]");

[Link]("Reminder: Follow up on " + position + " at " + company);

String html = "<div style='font-family:Arial;padding:20px;'>"

+ "<h2 style='color:#1A237E;'>Job Application Reminder</h2>"

+ "<p>Your application for <b>" + position + "</b> at <b>" + company

+ "</b> has had no updates in 7 days. Consider following up!</p>"

+ "</div>";

[Link](html, true); // true = is HTML

[Link](msg);

} catch (MessagingException e) {

throw new RuntimeException("Email failed", e);

}
CHAPTER 4

Spring Data JPA Deep Dive

Key Annotations
Annotation What It Does

@Entity Marks class as database table

@Table(name='...') Specifies exact table name

@Id Primary key field

@GeneratedValue(strategy=IDENTITY) Auto-increment PK

@Column(nullable=false, length=150) Column constraints

@Enumerated([Link]) Store enum as string in DB

@ManyToOne + @JoinColumn Foreign key relationship

@Lob Large text/binary column (TEXT in MySQL)

@CreationTimestamp Automatically set on INSERT

@UpdateTimestamp Automatically updated on every save()

@Where(clause='is_deleted=false') Soft delete auto-filter on all queries

@SQLDelete(sql='UPDATE ... SET is_deleted=true


Override DELETE
WHERE id=?')
with UPDATE

Custom Repository Queries


public interface JobApplicationRepository extends JpaRepository<JobApplication,
Long> {

// Derived query — Spring generates SQL from method name

Page<JobApplication> findByUserId(Long userId, Pageable pageable);

// Derived + multiple conditions

List<JobApplication> findByLastUpdatedBeforeAndReminderSentFalseAndIsDeletedFalse(

LocalDateTime threshold);

// Custom JPQL — count by status for analytics

@Query("SELECT [Link], COUNT(a) FROM JobApplication a "

+ "WHERE [Link] = :uid AND [Link] = false GROUP BY [Link]")

List<Object[]> countByStatus(@Param("uid") Long userId);

// Native SQL for date functions

@Query(value = "SELECT AVG(DATEDIFF(last_updated, applied_date)) "

+ "FROM job_applications WHERE user_id = :uid AND status IN ('INTERVIEW','OFFER')",

nativeQuery = true)

Double avgResponseDays(@Param("uid") Long userId);

}
CHAPTER 5

DTO Pattern and Mapping


Never return your entity directly from a controller. DTOs let you control exactly what data the API exposes,
decouple your API from your database schema, and add validation on inputs. This is a fundamental
pattern in production Java APIs.

Request DTO (what client sends)


@Getter @Setter

public class CreateJobApplicationRequest {

@NotBlank(message = "Company name required")

private String companyName;

@NotBlank private String position;

private String jobDescription;

private LocalDate appliedDate;

private String salaryRange;

private String jobUrl;

// No id, no userId, no status — server controls these

Response DTO (what API returns)


@Getter @Setter @Builder

public class JobApplicationResponse {

private Long id;

private String companyName;

private String position;

private ApplicationStatus status;

private LocalDate appliedDate;

private String salaryRange;

private boolean reminderSent;

private LocalDateTime lastUpdated;

// No user password, no is_deleted — clean and safe

Mapping entity to DTO


// In service — manual mapping using @Builder

private JobApplicationResponse toDto(JobApplication a) {

return [Link]()

.id([Link]()).companyName([Link]())

.position([Link]()).status([Link]())

.appliedDate([Link]()).salaryRange([Link]())

.reminderSent([Link]()).lastUpdated([Link]())
.build();

}
CHAPTER 6

Global Exception Handling


@RestControllerAdvice catches all exceptions thrown anywhere in your application and lets you return a
consistent, clean error response format. No controller needs try-catch blocks — all error handling is
centralized.

ErrorResponse DTO
@Getter @Setter @Builder

public class ErrorResponse {

private LocalDateTime timestamp;

private int status;

private String error;

private String message;

private String path;

Custom Exception Classes


public class ResourceNotFoundException extends RuntimeException {

public ResourceNotFoundException(String msg) { super(msg); }

public class InvalidStatusTransitionException extends RuntimeException {

public InvalidStatusTransitionException(String from, String to) {

super("Invalid transition: " + from + " -> " + to);

[Link]
@RestControllerAdvice

public class GlobalExceptionHandler {

@ExceptionHandler([Link])

@ResponseStatus(HttpStatus.NOT_FOUND)

public ErrorResponse handleNotFound(ResourceNotFoundException ex,

HttpServletRequest req) {

return [Link]().timestamp([Link]())

.status(404).error("Not Found")

.message([Link]()).path([Link]()).build();

@ExceptionHandler([Link])

@ResponseStatus(HttpStatus.BAD_REQUEST)

public ErrorResponse handleBadTransition(InvalidStatusTransitionException ex,


HttpServletRequest req) {

return [Link]().timestamp([Link]())

.status(400).error("Bad Request")

.message([Link]()).path([Link]()).build();

@ExceptionHandler([Link])

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

public ErrorResponse handleAll(Exception ex, HttpServletRequest req) {

return [Link]().timestamp([Link]())

.status(500).error("Server Error")

.message("Something went wrong").path([Link]()).build();

}
CHAPTER 7

Analytics and Aggregation Queries


Repository Queries
// Count applications by status

@Query("SELECT [Link], COUNT(a) FROM JobApplication a "

+ "WHERE [Link] = :uid AND [Link] = false GROUP BY [Link]")

List<Object[]> countByStatus(@Param("uid") Long userId);

// Average response time (native SQL for DATEDIFF)

@Query(value = "SELECT AVG(DATEDIFF(last_updated, applied_date)) "

+ "FROM job_applications WHERE user_id = :uid "

+ "AND status IN ('INTERVIEW','OFFER') AND is_deleted = 0", nativeQuery = true)

Double avgResponseDays(@Param("uid") Long userId);

// Applications by month

@Query("SELECT YEAR([Link]), MONTH([Link]), COUNT(a) "

+ "FROM JobApplication a WHERE [Link] = :uid AND [Link] = false "

+ "GROUP BY YEAR([Link]), MONTH([Link]) "

+ "ORDER BY YEAR([Link]), MONTH([Link])")

List<Object[]> countByMonth(@Param("uid") Long userId);

// Top companies (Pageable limits to top 5)

@Query("SELECT [Link], COUNT(a) as cnt FROM JobApplication a "

+ "WHERE [Link] = :uid AND [Link] = false "

+ "GROUP BY [Link] ORDER BY cnt DESC")

List<Object[]> topCompanies(@Param("uid") Long userId, Pageable pageable);

Processing in AnalyticsService
public AnalyticsSummaryDTO getSummary(Long userId) {

List<Object[]> rows = [Link](userId);

Map<String, Long> byStatus = new HashMap<>();

long total = 0; long offers = 0;

for (Object[] r : rows) {

String status = r[0].toString();

long count = ((Number) r[1]).longValue();

[Link](status, count);

total += count;

if ("OFFER".equals(status)) offers = count;

double rate = total > 0 ? (offers * 100.0 / total) : 0;

Double avgDays = [Link](userId);


return [Link]()

.totalApplications(total).successRate([Link](rate * 10) / 10.0)

.avgResponseDays(avgDays != null ? [Link]() : 0)

.byStatus(byStatus).build();

}
CHAPTER 8

Soft Delete Pattern


Hard deleting records corrupts analytics history. Soft delete marks records as deleted without removing
them, preserving all historical data. Hibernate handles this transparently with two annotations.

@Entity

@Where(clause = "is_deleted = false") // auto-appended to EVERY query

@SQLDelete(sql = "UPDATE job_applications SET is_deleted=true WHERE id=?")

public class JobApplication {

...

private boolean isDeleted = false;

// Now these work transparently:

[Link](app); // Runs UPDATE SET is_deleted=true (not DELETE)

[Link](); // Auto-filtered: WHERE is_deleted = false

[Link](1L); // Also filtered automatically

RESULT: When you call [Link](app), Hibernate runs UPDATE job_applications SET is_deleted=true
WHERE id=? instead of DELETE. When you query, @Where auto-adds is_deleted=false to every query.
Your analytics queries still see these records when they bypass @Where using nativeQuery=true.
CHAPTER 9

REST API Design Principles

HTTP Method Use For Status on Success

GET Fetch data, never changes state 200 OK

POST Create a new resource 201 Created

PUT Replace entire resource 200 OK

PATCH Update specific fields only 200 OK

DELETE Remove a resource (or soft delete) 204 No Content

Status Code Meaning When to Use

200 OK Successful GET, PUT, PATCH

201 Created POST that creates a new resource

204 No Content Successful DELETE

400 Bad Request Validation error, bad business rule

401 Unauthorized Missing or invalid JWT token

403 Forbidden Valid token but no access to this resource

404 Not Found Resource with given ID doesn't exist

409 Conflict Duplicate — email already registered

500 Internal Server Error Unexpected crash

Getting Current User from JWT in Controller


// Helper — put in a base class or utility

protected Long getCurrentUserId() {

Authentication auth = [Link]().getAuthentication();

String email = ((UserDetails) [Link]()).getUsername();

return [Link](email).orElseThrow().getId();

// CRITICAL: Always get userId from JWT, NEVER from request body

@PostMapping

public ResponseEntity<JobApplicationResponse> create(@RequestBody @Valid


CreateJobApplicationRequest req) {

Long userId = getCurrentUserId(); // From JWT — cannot be forged

return [Link](201).body([Link](userId, req));

}
CHAPTER 10

Unit Testing with JUnit and Mockito


Unit tests test one class in isolation. You mock all dependencies (repositories, services) so you test only
the logic of the class under test. No database, no Spring context, no network — just pure Java logic
verification.

Mockito Key Annotations

Annotation Purpose

@ExtendWith([Link]) Enable Mockito in the test class

@Mock Create a fake (mock) object — returns null by default

@InjectMocks Create the real class and inject @Mock fields into it

when(...).thenReturn(...) Tell a mock what to return when called

verify(mock, times(1)).method(...) Assert a method was called exactly once

assertThrows([Link], () -> ...) Assert that code throws a specific exception

assertThat(result).isEqualTo(expected) Assert values using AssertJ (fluent)

[Link]
@ExtendWith([Link])

class JobApplicationServiceTest {

@Mock private JobApplicationRepository repo;

@Mock private UserRepository userRepo;

@InjectMocks private JobApplicationService service;

@Test

void createApplication_shouldSaveAndReturnDto() {

User user = new User(); [Link](1L); [Link]("d@[Link]");

CreateJobApplicationRequest req = new CreateJobApplicationRequest();

[Link]("Google"); [Link]("Backend Engineer");

[Link]([Link]());

when([Link](1L)).thenReturn([Link](user));

when([Link](any())).thenAnswer(inv -> [Link](0));

JobApplicationResponse result = [Link](1L, req);

assertThat([Link]()).isEqualTo("Google");

assertThat([Link]()).isEqualTo([Link]);

verify(repo, times(1)).save(any([Link]));

@Test

void updateStatus_invalidTransition_shouldThrow() {
JobApplication app = new JobApplication();

[Link]([Link]);

when([Link](1L)).thenReturn([Link](app));

assertThrows([Link],

() -> [Link](1L, 1L, [Link]));

TESTING MINDSET: Each @Test method follows Arrange-Act-Assert. Arrange = set up mocks. Act = call the
method. Assert = verify the result. You are NOT testing the database or repository — you mock those. You
are testing that the SERVICE logic behaves correctly given controlled inputs.

QUICK REFERENCE — Spring Boot Annotations

Annotation Layer Purpose

@RestController Controller Combines @Controller + @ResponseBody — returns JSON

@Service Service Business logic layer bean

@Repository Repository Data access layer + JPA exception translation

@Component Any Generic Spring-managed bean

@Autowired Any Inject dependency (prefer constructor injection)

@Value Any Inject value from [Link]

@Transactional Service Wrap method in DB transaction — auto rollback on exception

@Valid Controller Trigger @NotBlank/@NotNull validation on request body

@PathVariable Controller Extract {id} from /api/items/{id}

@RequestParam Controller Extract ?page=0 query parameter

@RequestBody Controller Map JSON request body to Java object

@CrossOrigin Controller Allow CORS from React frontend origin

@Scheduled Component Auto-run method on schedule

@EnableScheduling Config/Main Enable @Scheduled processing

@NoArgsConstructor Entity Lombok: generate no-args constructor

@Getter @Setter Entity/DTO Lombok: generate all getters and setters

@Builder DTO Lombok: generate builder pattern

You might also like