title: No thread-bound request found with Spring when Kafka receive a message
body: <p>I 'm getting this error from my service </p>
  
  <pre><code>jvm org.hibernate.internal.ExceptionMapperStandardImpl {"@trace_info":"[availability-psql,eba16d49e23479cc,675789f41e0dda5b,eba16d49e23479cc,false]", "@message": "HHH000346: Error during managed flush [Error creating bean with name 'scopedTarget.infoUser': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.]
  </code></pre>
  
  <p>This is because of I have a bean of scope @ScopeRequest. This problem show up when a new message from kafka is received and I try to update my data base with spring data. If I remove my @Transactional I don't have any problem to save the data. </p>
  
  <pre><code>@KafkaListener(topics = "#{kafkaMastersConfig.topics}", containerFactory = "mastersContainerFactory")
    @Transactional
    @Authorized
    public void consumeWrapperMasterChangeEvent(@Payload String payload,
        @Header(KafkaHeaders.RECEIVED_TOPIC) String topic,  @Nullable @Header(AUTHORIZATION) String authorization) throws IOException {
      try {
      log.info("Received change event in masters: '{}'", payload);
  
      RequestAttributes context = RequestContextHolder.currentRequestAttributes();
      RequestContextHolder.setRequestAttributes(context);
  
      changeProcessorFactory.getEntityChangeProcessor(getEntityFromTopic(topic)).processChange(payload);
  
      } catch ( Exception e ) {
       log.error("Error proccesing message {} ", e.getMessage());
      } finally {
        RequestContextHolder.resetRequestAttributes();
      }
  
  
    }
  </code></pre>
  
  <p>And here is the bean:</p>
  
  <pre><code>@RequestScope
  @Component
  @NoArgsConstructor
  @Getter
  @Setter
  public class InfoUser {
  
    private DecodedJWT jwt;
  
    public String getCurrentUser() {
      if (jwt == null) {
        return null;
      }
      return jwt.getSubject();
    }
  
    public String getAuthorizationBearer() {
      if (jwt == null) {
        return null;
      }
      return jwt.getToken();
    }
  }
  </code></pre>
  
  <p>And this class:</p>
  
  <pre><code>public class CustomRequestScopeAttr implements RequestAttributes {
  
    private Map&lt;String, Object&gt; requestAttributeMap = new HashMap&lt;&gt;();
  
    @Override
    public Object getAttribute(String name, int scope) {
      if (scope == RequestAttributes.SCOPE_REQUEST) {
        return this.requestAttributeMap.get(name);
      }
      return null;
    }
  
    @Override
    public void setAttribute(String name, Object value, int scope) {
      if (scope == RequestAttributes.SCOPE_REQUEST) {
        this.requestAttributeMap.put(name, value);
      }
    }
  
    @Override
    public void removeAttribute(String name, int scope) {
      if (scope == RequestAttributes.SCOPE_REQUEST) {
        this.requestAttributeMap.remove(name);
      }
    }
  
    @Override
    public String[] getAttributeNames(int scope) {
      if (scope == RequestAttributes.SCOPE_REQUEST) {
        return this.requestAttributeMap.keySet().toArray(new String[0]);
      }
      return new String[0];
    }
  
    @Override
    public void registerDestructionCallback(String name, Runnable callback, int scope) {
      // Not Supported
    }
  
    @Override
    public Object resolveReference(String key) {
      // Not supported
      return null;
    }
  
    @Override
    public String getSessionId() {
      return null;
    }
  
    @Override
    public Object getSessionMutex() {
      return null;
    }
  }
  </code></pre>
  
  <p>And futhermore I have an aspect class to save the authorization token:</p>
  
  <pre><code>@Aspect
  @Component
  @RequiredArgsConstructor
  public class AuthorizationAspect {
  
    private final AuthorizationDecoder authorizationDecoder;
  
    private final ApplicationContext applicationContext;
  
    @Around("@annotation(Authorized)")
    public Object setInfoUser(ProceedingJoinPoint joinPoint) throws Throwable {
      try {
        String[] parameterNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
        Object[] args = joinPoint.getArgs();
        Map&lt;String, Object&gt; arguments = new HashMap&lt;&gt;();
        for (int i = 0; i &lt; args.length; i++) {
          if (null != args[i]) {
            arguments.put(parameterNames[i], args[i]);
          }
        }
        Object authorization = arguments.get("authorization");
        RequestContextHolder.setRequestAttributes(new CustomRequestScopeAttr());
  
        InfoUser infoUser = applicationContext.getBean(InfoUser.class);
        infoUser.setJwt(authorizationDecoder.decodeToken((String) authorization));
  
        return joinPoint.proceed();
  
      } finally {
        RequestContextHolder.resetRequestAttributes();
      }
  
    }
  </code></pre>
  
  <p>And the last class is trying to save de info:</p>
  
  <pre><code>@RequiredArgsConstructor
  public class RoomChangeMaster implements ChangeMaster&lt;Room&gt; {
  
    private final TimetableRepository timetableRepository;
  
    private final AvailabilityRepository availabilityRepository;
  
    @Override
    public void processChange(Room entity, ActionEnum action) {
  
      if (action == ActionEnum.updated) {
  
        List&lt;Timetable&gt; timetables = (List&lt;Timetable&gt;) timetableRepository.findByRoomId(entity.getId());
        Room room = timetables.get(0).getRoom();
        room.setDescription(entity.getDescription());
        room.setCode(entity.getCode());
        timetables.forEach(timetable -&gt; {
          timetable.setRoom(room);
          timetableRepository.save(timetable);
        });
  
        availabilityRepository
            .updateAvailabilityRoomByRoomId(room, entity.getId());
  
      } else {
  
        throw new IllegalStateException("Unexpected value: " + action);
  
      }
    }
  }
  </code></pre>
  
  <p>I have spent a lot of time finding out the problem, but so far, I was not able to know the problem. Any idea will be appreciate.</p>
  
  <p>Thank you</p>