DEV Community

Cover image for Java BeanUtils Copying: Convenient, but Not Free
Mark Yu
Mark Yu

Posted on • Edited on

Java BeanUtils Copying: Convenient, but Not Free

Bean copying looks harmless until it hides a production bug.

I have used BeanUtils.copyProperties() for DTO conversion because it is fast to write. Then later someone adds a nested object, a field name changes, or performance matters, and the convenient helper suddenly becomes a quiet source of confusion.

So here is the practical rule:

Use BeanUtils for simple, boring object copying. Do not use it as your default domain mapping strategy.

The Basic Copy

With Apache Commons BeanUtils:

import org.apache.commons.beanutils.BeanUtils;

public class CopyDemo {
    public static void main(String[] args) throws Exception {
        UserEntity entity = new UserEntity("Mark", 30);
        UserDTO dto = new UserDTO();

        BeanUtils.copyProperties(dto, entity);

        System.out.println(dto);
    }
}
Enter fullscreen mode Exit fullscreen mode

That is the reason people like it. One line replaces a bunch of setters.

But the hidden question is:

What exactly did it copy?

Shallow Copy Is the First Trap

If the object contains nested objects, BeanUtils copies the reference. It does not magically deep-copy your object graph.

class UserEntity {
    private String name;
    private Address address;
}

class UserDTO {
    private String name;
    private Address address;
}
Enter fullscreen mode Exit fullscreen mode

After copying, both objects can point at the same Address.

That may be fine. It may also be a bug if one layer mutates the nested object.

Visual map:

UserEntity.address ----+
                       +----> same Address object
UserDTO.address -------+
Enter fullscreen mode Exit fullscreen mode

If you need independent nested objects, write that mapping explicitly or use a mapper designed for it.

Reflection Has a Cost

BeanUtils usually relies on reflection and runtime property inspection.

That means:

  • less compile-time safety
  • slower mapping than direct code
  • mistakes may show up later
  • refactoring fields can be riskier

For one admin endpoint, who cares.

For mapping thousands of rows in a hot path, I would care.

Spring BeanUtils vs Apache BeanUtils

The method names look similar, but behavior differs.

Tool Good for Watch out
Spring BeanUtils simple same-name copy limited conversion
Apache BeanUtils string conversion and dynamic property access reflection overhead
MapStruct production DTO mapping setup and annotations
Manual mapping critical domain logic more code

My current preference:

  • quick internal tools: BeanUtils
  • API DTO mapping: MapStruct or manual mapping
  • sensitive business logic: manual mapping

A Safer DTO Mapping Example

Sometimes boring explicit code is better:

public UserDTO toDto(UserEntity entity) {
    UserDTO dto = new UserDTO();
    dto.setName(entity.getName());
    dto.setAge(entity.getAge());

    if (entity.getAddress() != null) {
        AddressDTO address = new AddressDTO();
        address.setCity(entity.getAddress().getCity());
        address.setCountry(entity.getAddress().getCountry());
        dto.setAddress(address);
    }

    return dto;
}
Enter fullscreen mode Exit fullscreen mode

Yes, it is longer.

But during a code review, nobody has to guess what happens to address.

Where BeanUtils Still Makes Sense

I would still use it for:

  • small admin tools
  • test fixtures
  • simple JavaBean-to-JavaBean copying
  • prototypes
  • non-critical internal scripts

I would avoid it for:

  • hot paths
  • payment/order domain mapping
  • complex nested DTOs
  • security-sensitive field filtering
  • APIs where fields change often

Production Pitfall: Copying Too Much

This bug is easy to miss:

BeanUtils.copyProperties(userEntity, requestDto);
Enter fullscreen mode Exit fullscreen mode

If requestDto contains fields like role, status, or createdAt, you may accidentally let user input overwrite fields it should not control.

For request-to-entity updates, I prefer explicit allow-list mapping:

user.setDisplayName(request.getDisplayName());
user.setBio(request.getBio());
Enter fullscreen mode Exit fullscreen mode

It is less clever. It is safer.

Final Thought

BeanUtils is a convenience tool, not an architecture.

Use it where the mapping is boring. When the mapping carries business meaning, write it so the next developer can see every decision.

Have you ever had a DTO copy bug caused by a field you did not mean to map?

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.