0

I have parametrised interface and parametrised class that implements this interface. Than I inject this class into 3 services and set typeParameterClass in @PostConstruct method. 2 classes return correct typeParameterClass, but other one returns typeParameterClass from another service and not the one that was setted in this class in @PostConstruct.

Like

ClassOneServiceImpl.getParameter() = ClassOne.class;
ClassTwoServiceImpl.getParameter() = ClassTwo.class;
ClassThreeServiceImpl.getParameter() = ClassOne.class;

I've added logging to initialisation, however I see that setted TypeParameterClass in setTypeParameterClass(Class clazz) is correct.

In local environment on jdk-17 Temurin the program is working fine.

Any suggestions why @PostCOnstruct not working as expected? Or may be the problem can occur in other places?

public interface PostgresDAO<T> {
    void setTypeParameterClass(Class<T> clazz);
    Entity findEntityById(Long id);
}


@Repository
@NoArgsConstructor
@Getter
public class PostgresDAOImpl<T> implements PostgresDAO<T> {

    private Class<T> typeParameterClass

    @PersistenceContext
    private EntityManager em;

    @Override
    public void setTypeParameterClass(Class<T> clazz) {
        this.typeParameterClass = clazz;
    }

    **** some code with EntityManager
    
}

And I have 3 services that are using PostgresDAOImpl with different parameter.

@Service
@RequiredArgsConstructor
public class ClassOneServiceImpl implements ClassOneService {

    private final PostgresDAO<ParameterOne> dao;

    @PostConstruct
    public void enrichDao() {
        dao.setTypeParameterClass(ParameterOne.class);
    }

    public Class getParameter() {
        return dao.getTypeParameterClass();
    }

    ***** some code

}


@Service
@RequiredArgsConstructor
public class ClassTwoServiceImpl implements ClassTwoService {

    private final PostgresDAO<ParameterTwo> dao;

    @PostConstruct
    public void enrichDao() {
        dao.setTypeParameterClass(ParameterTwo.class);
    }

    public Class getParameter() {
        return dao.getTypeParameterClass();
    }

    ***** some code

}


@Service
@RequiredArgsConstructor
public class ClassThreeServiceImpl implements ClassThreeService {

    private final PostgresDAO<ParameterThree> dao;

    @PostConstruct
    public void enrichDao() {
        dao.setTypeParameterClass(ParameterThree.class);
    }

    public Class getParameter() {
        return dao.getTypeParameterClass();
    }

    ***** some other code

}

javax.annotation dependency added

        <!--need for postconstruct annotation in java 11 https://www.baeldung.com/spring-postconstruct-predestroy-->
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>

Setup

  • lombok 1.18.22
  • spring-boot 2.7.0

openjdk version "11.0.4" 2019-07-16 LTS

OpenJDK Runtime Environment 18.9 (build 11.0.4+11-LTS)

OpenJDK 64-Bit Server VM 18.9 (build 11.0.4+11-LTS, mixed mode, sharing)

Answer code:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PostgresDAOConfig {
    @Bean
    public PostgresDAO<ParameterOne> deceptionDAO() {
        PostgresDAOImpl<ParameterOne> result = new PostgresDAOImpl<>();
        result.setParameterClass(ParameterOne.class);
        return result;
    }
    @Bean
    public PostgresDAO<ParameterTwo> deceptionDAO() {
        PostgresDAOImpl<ParameterTwo> result = new PostgresDAOImpl<>();
        result.setParameterClass(ParameterTwo.class);
        return result;
    }
    @Bean
    public PostgresDAO<ParameterThree> deceptionDAO() {
        PostgresDAOImpl<ParameterThree> result = new PostgresDAOImpl<>();
        result.setParameterClass(ParameterThree.class);
        return result;
    }
}
Alex A
  • 33
  • 5

1 Answers1

1

I am surprised it works locally because it should not. By default Spring beans are singletons and with your code example you inject the same bean in all ClassOne, ClassTwo and ClassThree services. In the PostConstruct method you just override the parameter class.

To address this, you create three PostgresDAOImpl repositories in a @Configuration annotated class and inject each one in the relevant service. If you go like this most likely you don't even need the PostConstruct method at all.

Julian
  • 3,678
  • 7
  • 40
  • 72