<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ginto Philip</title>
    <description>The latest articles on DEV Community by Ginto Philip (@gintop).</description>
    <link>https://dev.to/gintop</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3637569%2F883961ad-67ca-41f7-ab2a-9c3342d19295.png</url>
      <title>DEV Community: Ginto Philip</title>
      <link>https://dev.to/gintop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gintop"/>
    <language>en</language>
    <item>
      <title>Building a Simple Plugin Architecture in Java Using the Java SPI Mechanism</title>
      <dc:creator>Ginto Philip</dc:creator>
      <pubDate>Sun, 30 Nov 2025 15:36:00 +0000</pubDate>
      <link>https://dev.to/gintop/building-a-simple-plugin-architecture-in-java-using-the-java-spi-mechanism-5234</link>
      <guid>https://dev.to/gintop/building-a-simple-plugin-architecture-in-java-using-the-java-spi-mechanism-5234</guid>
      <description>&lt;p&gt;Software systems often grow over time, and with growth comes the need for flexibility. You might want to add new features, support new formats, or integrate with new systems without modifying the core application each time. This is exactly where a &lt;strong&gt;plugin architecture&lt;/strong&gt; shines.&lt;/p&gt;

&lt;p&gt;In this post, we’ll walk through how to build a &lt;strong&gt;lightweight plugin architecture&lt;/strong&gt; using &lt;strong&gt;Java’s Service Provider Interface (SPI)&lt;/strong&gt;. We’ll also describe a practical example involving greeting messages in multiple languages.&lt;/p&gt;

&lt;p&gt;The main objective of this post is to make people familiarize with the plugin architecture in a simple way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Plugin Architecture?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Plugin Architecture&lt;/strong&gt; is a software design pattern that allows for the core functionality of an application to be extended, modified, or customized without changing the core application's source code.&lt;/p&gt;

&lt;p&gt;New functionality is packaged as small, independent modules called &lt;strong&gt;plugins&lt;/strong&gt;, which the main application discovers and loads at runtime.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Core Application (Platform):&lt;/strong&gt; This is the stable, main part of the software. It defines a set of &lt;strong&gt;contracts&lt;/strong&gt; (interfaces or abstract classes) that external components must adhere to. It provides the mechanism to discover and load extensions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plugins (Extensions):&lt;/strong&gt; These are external, self-contained modules that implement the contracts defined by the core application. They provide the actual extension logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Use a Plugin Architecture?
&lt;/h3&gt;

&lt;p&gt;Using this architecture offers several significant advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extensibility:&lt;/strong&gt; New features can be added rapidly by simply deploying new plugins, without rebuilding or redeploying the entire core application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decoupling/Modularity:&lt;/strong&gt; It separates concerns, making the core platform smaller, more stable, and easier to maintain. Plugins can be developed and updated independently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Third-Party Integration:&lt;/strong&gt; It enables third parties to build extensions for your platform (e.g., IDE extensions, browser add-ons).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Complexity:&lt;/strong&gt; Allows teams to work on specific features in isolation, leading to cleaner codebases.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real-world examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;IntelliJ / Eclipse extensions
&lt;/li&gt;
&lt;li&gt;Browser extensions
&lt;/li&gt;
&lt;li&gt;Payment gateways in e-commerce platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Is Java SPI (Service Provider Interface)?
&lt;/h3&gt;

&lt;p&gt;Java’s &lt;strong&gt;SPI&lt;/strong&gt; is a built-in mechanism that enables &lt;em&gt;loose coupling&lt;/em&gt; between an API (interface) and its implementations. It allows an application (the core Platform) to load implementations (the Plugins) of an interface or abstract class (the Contract) that are provided by external JAR files at runtime.&lt;/p&gt;

&lt;p&gt;It allows applications to &lt;strong&gt;discover implementations at runtime&lt;/strong&gt; using simple configuration files.&lt;/p&gt;

&lt;p&gt;At a high level, SPI involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service:&lt;/strong&gt; An interface or abstract class known to the application and implemented by the plugins. In the project, this is the &lt;code&gt;GreetingPlugin&lt;/code&gt; interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service Provider:&lt;/strong&gt; A specific implementation of the Service (e.g., &lt;code&gt;SpanishGreeting&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service Loader:&lt;/strong&gt; A core Java class (&lt;code&gt;java.util.ServiceLoader&lt;/code&gt;) that the application uses to discover and load all available Service Providers for a given Service interface.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For the SPI to work:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Plugins must contain a special file in the &lt;code&gt;META-INF/services/&lt;/code&gt; directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The file's name &lt;strong&gt;must&lt;/strong&gt; be the fully qualified name of the &lt;strong&gt;Service interface&lt;/strong&gt; (the Contract).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eg: &lt;code&gt;com.gintophilip.core.greeting.contract.GreetingPlugin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;The content of this file is a list of the fully qualified class names of the &lt;strong&gt;Service Provider implementations&lt;/strong&gt; within that JAR.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;com.gintophilip.spanishgreeting.SpanishGreeting   com.gintophilip.hindigreeting.HindiGreeting&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Project Structure and Implementation Overview
&lt;/h3&gt;

&lt;p&gt;The project is divided into three modules,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plugin Platform (Core Application)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plugin Platform Contracts (Interfaces / Contracts)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plugin Implementations (Actual Plugins)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Plugin Platform (Core Application)
&lt;/h3&gt;

&lt;p&gt;This is the main application. Its primary task is to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Manage users (simulated database with hardcoded users)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide a CLI interface (Login, show user details, quit)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the &lt;code&gt;ServiceLoader&lt;/code&gt; to discover and load the available &lt;code&gt;GreetingPlugin&lt;/code&gt; implementations at runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delegate greeting responsibility to the appropriate plugin based on user language&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Responsibilities:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; Reads the configured plugin folder location (e.g., &lt;code&gt;plugins/&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Plugin Discovery and Loading:&lt;/strong&gt; At startup, it needs to find the plugin JARs in the folder and use &lt;code&gt;ServiceLoader&lt;/code&gt; to load all implementations of &lt;code&gt;GreetingPlugin&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The core component for using the plugins, like &lt;code&gt;UserGreeter&lt;/code&gt;, will utilize &lt;code&gt;ServiceLoader.load(GreetingPlugin.class)&lt;/code&gt; to get an iterable of all available plugin instances.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Plugin Selection and Execution (The&lt;/strong&gt; &lt;code&gt;UserGreeter&lt;/code&gt; Logic):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a user logs in, the &lt;code&gt;UserGreeter&lt;/code&gt; logic fetches the user's preferred language (&lt;code&gt;currentUser.getPreferredLanguage()&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;It iterates through the loaded &lt;code&gt;GreetingPlugin&lt;/code&gt; instances.
&lt;/li&gt;
&lt;li&gt;It finds the plugin where &lt;code&gt;plugin.getLanguage()&lt;/code&gt; matches the user's preferred language.
&lt;/li&gt;
&lt;li&gt;If a match is found, it calls &lt;code&gt;plugin.greet(userName)&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;If no matching plugin is found (or no preferred language is set), it falls back to the default English greeting implementation provided by the core platform itself.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLI Interface:&lt;/strong&gt; Provides the basic interaction loop (&lt;code&gt;L&lt;/code&gt; for login, &lt;code&gt;D&lt;/code&gt; for details, &lt;code&gt;q!&lt;/code&gt; to quit).&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Plugin Platform Contracts (The Service)
&lt;/h3&gt;

&lt;p&gt;This module defines the public interface that all plugins must implement. It's the &lt;strong&gt;Service&lt;/strong&gt; in the SPI pattern. It must be packaged as a JAR and be a dependency for both the Core Platform and the Plugin Implementations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contract Interface:&lt;/strong&gt; &lt;code&gt;GreetingPlugin&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;GreetingPlugin&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getLanguage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This contract defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;greet(...)&lt;/strong&gt; → Logic to greet the user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getLanguage()&lt;/strong&gt; → A unique identifier for the language this plugin supports&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Plugin Implementations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This project contains concrete plugin classes in our case, a &lt;strong&gt;Spanish&lt;/strong&gt; and a &lt;strong&gt;Hindi&lt;/strong&gt; greeter. These are the actual, deployable extensions. They depend only on the &lt;strong&gt;Contracts&lt;/strong&gt; module. They do not need to know anything about the &lt;strong&gt;Platform&lt;/strong&gt; module.&lt;/p&gt;

&lt;p&gt;Each plugin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Depends on &lt;em&gt;Plugin Platform Contracts&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implements &lt;code&gt;GreetingPlugin&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Has a provider configuration file&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this project we provide two implemntations→ &lt;code&gt;SpanishGreeting&lt;/code&gt; and &lt;code&gt;HindiGreeting&lt;/code&gt; Both implementations are provided in a single JAR.&lt;/p&gt;

&lt;p&gt;The plugin JAR must contain the following file structure and content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Location:&lt;/strong&gt; &lt;code&gt;resources/META-INF/services/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Name:&lt;/strong&gt; &lt;code&gt;com.gintophilip.core.greeting.contract.GreetingPlugin&lt;/code&gt; (using the fully qualified name of the contract interface).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Content:&lt;/strong&gt; (Listing all implementations in the JAR)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;com.gintophilip.core.greeting.plugin.SpanishGreeting com.gintophilip.core.greeting.plugin.HindiGreeting&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once packaged as a JAR and dropped into the &lt;code&gt;plugins/&lt;/code&gt; folder, the platform picks them up automatically at startup.&lt;/p&gt;

&lt;p&gt;Here is a gist of the code&lt;/p&gt;

&lt;h3&gt;
  
  
  The contract
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;GreetingPlugin&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getLanguage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpanishGreeting&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;GreetingPlugin&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hola "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;"bienvenido"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getLanguage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Spanish"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loading the plugin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loadPlugins&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;loadDefaultPlugin&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;pluginDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PLUGIN_DIRECTORY&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;pluginDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exists&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pluginDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDirectory&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[PluginRepository] Plugin directory not found: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pluginDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAbsolutePath&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;jarFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pluginDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listFiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JarFileFilter&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jarFiles&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;jarFiles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[PluginRepository] No plugin JARs found in: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pluginDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAbsolutePath&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;jarFile&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jarFiles&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;loadPluginFromJar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jarFile&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greetingPluginsMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[PluginRepository] No valid GreetingPlugins loaded."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loadPluginFromJar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;jarFile&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;URL&lt;/span&gt; &lt;span class="n"&gt;jarUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jarFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toURI&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toURL&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;URLClassLoader&lt;/span&gt; &lt;span class="n"&gt;classLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLClassLoader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="n"&gt;jarUrl&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getClassLoader&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;ServiceLoader&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GreetingPlugin&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;serviceLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="nc"&gt;ServiceLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GreetingPlugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GreetingPlugin&lt;/span&gt; &lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serviceLoader&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;addPlugin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[PluginRepository] Loaded plugin: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MalformedURLException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[PluginRepository] Invalid plugin URL: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;jarFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAbsolutePath&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[PluginRepository] Failed to load plugin from: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;jarFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAbsolutePath&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The code for each module is available in github:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Plugin Platform: &lt;a href="https://github.com/bytealizer/PluginPlatform" rel="noopener noreferrer"&gt;https://github.com/bytealizer/PluginPlatform&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plugin Platform Contracts: &lt;a href="https://github.com/bytealizer/PluginPlatformContracts" rel="noopener noreferrer"&gt;https://github.com/bytealizer/PluginPlatformContracts&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plugin Implementation: &lt;a href="https://github.com/bytealizer/SPHNGreeting" rel="noopener noreferrer"&gt;https://github.com/bytealizer/SPHNGreeting&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How to run this project:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Clone the three repositories above. Then,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build the Plugin Platform Contracts module.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the build completes, a JAR file named &lt;code&gt;PluginPlatformContracts-1.0-SNAPSHOT.jar&lt;/code&gt; will appear in the &lt;code&gt;build&lt;/code&gt; folder.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add the contracts JAR to both the Plugin Platform and Plugin Implementation projects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In each project’s &lt;code&gt;build.gradle&lt;/code&gt;, add the following dependency:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;files&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nc"&gt;PluginPlatformContracts&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;SNAPSHOT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jar&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure that a &lt;code&gt;libs&lt;/code&gt; folder exists in each project; create it if necessary.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwz4qciatpior3bfvq9v1.png" alt="libs folder" width="696" height="72"&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Build the Plugin Implementation module.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This will generate a JAR file named &lt;code&gt;SPHNGreeting-1.0-SNAPSHOT.jar&lt;/code&gt; in its &lt;code&gt;build&lt;/code&gt; folder.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Deploy the plugin.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copy the generated &lt;code&gt;SPHNGreeting-1.0-SNAPSHOT.jar&lt;/code&gt; into the &lt;code&gt;plugins&lt;/code&gt; folder of the Plugin Platform.&lt;/p&gt;

&lt;p&gt;The location of the plugin directory is configured in the variable &lt;code&gt;PLUGIN_DIRECTORY&lt;/code&gt; in the &lt;code&gt;PluginRepository&lt;/code&gt; class. You can change the value here&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk917k2ags37vnyzrz5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk917k2ags37vnyzrz5e.png" alt="plugin" width="696" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run the Plugin Platform application.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Launch &lt;code&gt;Main.java&lt;/code&gt; in the Plugin Platform. Once the application starts and the CLI becomes visible, type &lt;code&gt;L&lt;/code&gt;, then enter a username and password for a user. You should see the greeting produced by the plugin.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q6bsrsedynyhr12bpqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q6bsrsedynyhr12bpqe.png" alt="output" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the hard coded user details:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;First Name&lt;/th&gt;
&lt;th&gt;Last Name&lt;/th&gt;
&lt;th&gt;Username&lt;/th&gt;
&lt;th&gt;Password&lt;/th&gt;
&lt;th&gt;Preferred Language&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;John&lt;/td&gt;
&lt;td&gt;Doe&lt;/td&gt;
&lt;td&gt;jdoe&lt;/td&gt;
&lt;td&gt;password123&lt;/td&gt;
&lt;td&gt;NONE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;Smith&lt;/td&gt;
&lt;td&gt;asmith&lt;/td&gt;
&lt;td&gt;alicePass&lt;/td&gt;
&lt;td&gt;Hindi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;Johnson&lt;/td&gt;
&lt;td&gt;bjohnson&lt;/td&gt;
&lt;td&gt;securePass&lt;/td&gt;
&lt;td&gt;NONE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emma&lt;/td&gt;
&lt;td&gt;Brown&lt;/td&gt;
&lt;td&gt;ebrown&lt;/td&gt;
&lt;td&gt;hello123&lt;/td&gt;
&lt;td&gt;Spanish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Liam&lt;/td&gt;
&lt;td&gt;Wilson&lt;/td&gt;
&lt;td&gt;lwilson&lt;/td&gt;
&lt;td&gt;mypassword&lt;/td&gt;
&lt;td&gt;NONE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each user will be greeted in following language as listed in the below table&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Username&lt;/th&gt;
&lt;th&gt;Preferred Language&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;jdoe&lt;/td&gt;
&lt;td&gt;English. [NONE is given defaults to English]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;asmith&lt;/td&gt;
&lt;td&gt;Hindi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bjohnson&lt;/td&gt;
&lt;td&gt;English. [NONE is given defaults to English]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ebrown&lt;/td&gt;
&lt;td&gt;Spanish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lwilson&lt;/td&gt;
&lt;td&gt;English. [NONE is given defaults to English]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How Plugins Are Packaged and Deployed&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To deploy a plugin:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Build the plugin project into a JAR&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure it contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; implementation classes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;META-INF/services/...&lt;/code&gt; provider file&lt;/li&gt;
&lt;li&gt;The contract dependency&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the JAR into the configurable plugin directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Restart the core application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The new language is now supported with &lt;em&gt;no code changes&lt;/em&gt; to the core app&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Happy Coding and Exploring Plugins!&lt;/strong&gt;🎉&lt;/p&gt;

&lt;p&gt;Remember, building plugin architectures is not just about adding features, it’s about designing software that can grow gracefully over time. Every new plugin you create is a small step toward mastering modular, flexible, and maintainable Java applications. Keep experimenting, keep learning, and enjoy the journey!&lt;/p&gt;

</description>
      <category>java</category>
      <category>webdev</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
