eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Introduction

In Java, the URLConnection class provides basic functionality for connecting to resources specified by a URL. However, in certain scenarios, developers may need a custom implementation to tailor the connection to specific requirements. In this tutorial, we’ll explore the process of creating a custom URL connection.

2. Why Create a Custom URL Connection

Creating a custom URL connection becomes imperative due to various limitations associated with the default URLConnection class. In this section, we’ll discuss these limitations and outline scenarios where customization is necessary.

2.1. Addressing Protocol Limitations

The default URLConnection class provides a fundamental mechanism for connecting to resources via a URL. It was designed primarily for HTTP and HTTPS protocols. In cases where an application needs to interact with resources using custom protocols developed within an organization or for specific applications, a custom connection is imperative. For example, we might need to connect to a company’s internal network protocol or a custom database protocol.

2.2. Limited Authentication Methods

The default URL connection classes support common authentication methods, such as basic authentication and digest authentication, which are suitable for many web-based applications. However, in more complex scenarios, such as token-based authentication in modern applications, default URL connection classes might not seamlessly handle the intricacies of token-based authentication.

2.3. Handling Resource-Specific Requirements

In some cases, the resources we interact with may have specific requirements. This could involve setting custom headers, adhering to unique authentication protocols, or managing specific encoding and decoding mechanisms. The default connection doesn’t provide the necessary control over the header configuration.

3. Use Case

Let’s envision a scenario where our organization operates a legacy system utilizing a proprietary internal protocol for data exchange. Unlike the commonly used HTTP or HTTPS, the internal protocol was using myprotocol, and this is the sample URL:

myprotocol://example.com/resource

This URL structure reflects the unique protocol myprotocol and points to a specific resource /resource hosted on the domain example.com. However, the challenge arises when our application, which uses the standard web protocols, needs to interact with this legacy system.

To overcome this incompatibility and establish communication between our application and the legacy system, we must implement a custom URL connection tailored to handle the proprietary protocol, myprotocol. This custom connection will act as a bridge, enabling seamless data exchange and integration between the two systems.

4. Implementation

In this section, we’ll delve into the code implementation of creating a custom URL connection.

4.1. Create a CustomURLConnection

To create a custom URL connection, we need to extend the java.net.URLConnection class and implement the necessary methods to tailor the connection to our specific requirements. This class will serve as the foundation of our custom connection:

public class CustomURLConnection extends URLConnection {
    private String simulatedData = "This is the simulated data from the resource.";
    private URL url;
    private boolean connected = false;
    private String headerValue = "SimulatedHeaderValue";
    // implementation details 
}

Next, let’s create a constructor for our class that takes a URL as a parameter. It calls the constructor of the superclass URLConnection with the provided URL:

protected CustomURLConnection(URL url) {
    super(url);
    this.url = url;
}

Let’s implement the commonly used methods in our CustomURLConnection class. In the connect() method, we establish the physical connection to the resource. This might involve opening a network socket or performing any necessary setup:

@Override
public void connect() throws IOException {
    connected = true;
    System.out.println("Connection established to: " + url);
}

The getInputStream() method is called when input from the resource is required. In our implementation, we simulate the data by returning an input stream from a ByteArrayInputStream containing simulated data:

@Override
public InputStream getInputStream() throws IOException {
    if (!connected) {
        connect();
    }
    return new ByteArrayInputStream(simulatedData.getBytes());
}

The getOutputStream() method is called when writing data to the resource. In our implementation, we return an output stream for writing to a ByteArrayOutputStream:

@Override
public OutputStream getOutputStream() throws IOException {
    ByteArrayOutputStream simulatedOutput = new ByteArrayOutputStream();
    return simulatedOutput;
}

The getContentLength() method returns the content length of the resource. In our case, we return the length of the simulated data string:

@Override
public int getContentLength() {
    return simulatedData.length();
}

The getHeaderField() method is used to retrieve the value of a specific header field from the response. In our implementation, we provide a simulated header value for the SimulatedHeader field:

@Override
public String getHeaderField(String name) {
    if ("SimulatedHeader".equalsIgnoreCase(name)) { 
        return headerValue;
    } else {
        return null; 
    } 
}

4.2. Create a URLStreamHandler

Next, we’ll create a class named CustomURLStreamHandler that extends URLStreamHandler. This class acts as a bridge between our custom URL and the actual connection process.

There are a few key methods we need to implement:

  • openConnection(): This method is responsible for creating and returning an instance of our custom URLConnection class. It acts as a factory for creating connections to the resource specified by the URL.
  • parseURL(): This method breaks down a given URL into its components such as protocol, host, and path. This is essential for the proper functioning of the URL.
  • setURL(): This method is used to set the URL for the stream handler. It is called during the process of constructing a URL object, and it sets the individual components of the URL.

Let’s create our CustomURLStreamHandler class:

class CustomURLStreamHandler extends URLStreamHandler {
    @Override
    protected URLConnection openConnection(URL u) {
        return new CustomURLConnection(u);
    }

    @Override
    protected void parseURL(URL u, String spec, int start, int limit) {
        super.parseURL(u, spec, start, limit);
    }

    @Override
    protected void setURL(URL u, String protocol, String host, int port, String authority, 
      String userInfo, String path, String query, String ref) {
        super.setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
    }
}

4.3. Register the URLStreamHandlerFactory

Next, we need to register a custom URLStreamHandlerFactory. This factory will be responsible for creating instances of our URLStreamHandler whenever Java encounters a URL with our custom protocol:

class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
    @Override
    public URLStreamHandler createURLStreamHandler(String protocol) {
        if ("myprotocol".equals(protocol)) {
            return new CustomURLStreamHandler();
        }
        return null;
    }
}

5. Testing

Now that we’ve implemented our custom URL connection, it’s crucial to run the program and validate its functionality.

The first step is to register our custom URLStreamHandlerFactory by calling the setURLStreamHandlerFactory() method:

URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());

Now, let’s create a URL object using our custom protocol and open a connection to it:

URL url = new URL("myprotocol://example.com/resource");
CustomURLConnection customConnection = (CustomURLConnection) url.openConnection();

With the factory registered, Java will use our CustomURLStreamHandler whenever it encounters a URL with the myprotocol custom protocol. Before interacting with the resource, we need to explicitly establish the connection. Add the following line to invoke the connect() method:

customConnection.connect();

To verify that our custom connection can retrieve content from the resource, we’ll read the input stream. We’ll use a Scanner to convert the stream into a string:

InputStream inputStream = customConnection.getInputStream();
String content = new Scanner(inputStream).useDelimiter("\\A").next();
System.out.println(content);

Additionally, let’s check if our custom connection correctly reports the content length:

int contentLength = customConnection.getContentLength();
System.out.println("Content Length: " + contentLength);

Finally, let’s get the value of the custom header from the custom connection:

String headerValue = customConnection.getHeaderField("SimulatedHeader");
System.out.println("Header Value: " + headerValue);

Now, we can run the entire program and observe the output in the console:

Connection established to: myprotocol://example.com/resource
This is the simulated data from the resource.
Content Length: 45
Header Value: SimulatedHeaderValue

6. Conclusion

In this article, we explored the process of creating a custom URL connection in Java to overcome the limitations associated with the default URLConnection class. We identified scenarios where customization becomes crucial, such as addressing protocol limitations, accommodating varied authentication methods, and handling resource-specific requirements.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)