Problem z zapisywaniem encji

0

kod: https://github.com/trolololololo4/bellaputanesca/tree/master/bella-core/src/main/java/com/julian/bella

Driver extends Employee , Shipper extends Employee, CallCenterConsultant extends Employee

Gdy próbuję zapisać drivera `driverRepository.save(driver)' to on się próbuje zapisać jako Shipper. Jak usunę Shippera, mapowanie Shipper, itd. o zapisuje się prawidłowo jako Driver.

Nawet nie mogę pobrać listy zapisanych Driverów przy inicjacji (pakiet init) bo dostaję:

"status": 500,
"error": "Internal Server Error",
"message": "com.julian.bellaapi.dto.ShipperDto cannot be cast to com.julian.shipper.api.dto.DriverDto",

0

Najlepiej pokaż cały stacktrace jaki leci przy save.

Jaki ma cel poniższa adnotacja na dto?

@Component
public class DriverDto extends EmployeeDto {

}
@Component
public class ShipperDto extends EmployeeDto {

}
0
Seti87 napisał(a):

Najlepiej pokaż cały stacktrace jaki leci przy save.

Jaki ma cel poniższa adnotacja na dto?

@Component
public class DriverDto extends EmployeeDto {

}
@Component
public class ShipperDto extends EmployeeDto {

}

być może w przyszłości Driver będzie miał jakieś swoje pole w stylu Vehicle a Shippper go nie będzie miał.


java.lang.ClassCastException: com.julian.bella.api.dto.ShipperDto cannot be cast to com.julian.bella.api.dto.DriverDto
	at com.julian.bella.api.mapper.DriverMapper.sourceToDto(DriverMapper.java:23) ~[classes/:na]
	at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source) ~[na:1.8.0_181]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source) ~[na:1.8.0_181]
	at java.util.stream.AbstractPipeline.copyInto(Unknown Source) ~[na:1.8.0_181]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) ~[na:1.8.0_181]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source) ~[na:1.8.0_181]
	at java.util.stream.AbstractPipeline.evaluate(Unknown Source) ~[na:1.8.0_181]
	at java.util.stream.ReferencePipeline.collect(Unknown Source) ~[na:1.8.0_181]
	at com.julian.bella.services.DriverServiceImpl.getAllDrivers(DriverServiceImpl.java:33) ~[classes/:na]
	at com.julian.bella.controllers.DriverController.getAllClients(DriverController.java:33) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_181]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_181]
	at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_181]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_181]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_181]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.34.jar:8.5.34]
	at java.lang.Thread.run(Unknown Source) [na:1.8.0_181]
1

Strzelam że wstrzykujesz ten sam baseMapper do obu poniższych mapperów i nadpisujesz sobie source class i dto class.

@Autowired
	public ShipperMapper(EmployeeBaseMapper<Shipper, ShipperDto> baseMapper) {
		this.baseMapper = baseMapper;
		baseMapper.setSourceClassType(Shipper.class);
		baseMapper.setDtoClassType(ShipperDto.class);
	}
@Autowired
	public DriverMapper(EmployeeBaseMapper<Driver, DriverDto> baseMapper) {
		this.baseMapper = baseMapper;
		baseMapper.setSourceClassType(Driver.class);
		baseMapper.setDtoClassType(DriverDto.class);
	}

Nie korzystałem z mapperów, ale podejrzewam że DriverMapper powinien dziedziczyć po EmployeeBaseMapper.
Tak samo ShipperMapper powinien dziedziczyć po EmployeeBaseMapper i dodatkowo zdejmujesz @Component z EmployeeBaseMapper.

Edit:

Julian_ napisał(a):

być może w przyszłości Driver będzie miał jakieś swoje pole w stylu Vehicle a Shippper go nie będzie miał.

Okej, ale to dalej nie wyjaśnia dlaczego masz @Component na obu klasach :)

0

Nie mogę zrobić dziedziczenia, bo wtedy nie zapodam 2 razy interfejsów GenericMapper.
Już na prawdę nie wiem o co chodzi...

zmieniłem mappera Employee na:

@Component
public class EmployeeBaseMapper implements GenericMapper<Employee, EmployeeDto> {

	UserMapper userMapper;

	@Autowired
	public EmployeeBaseMapper(UserMapper userMapper) {
		this.userMapper = userMapper;
	}

	@Override
	public EmployeeDto sourceToDto(Employee source) {
		if (source == null) {
			return null;
		}
		UserDto userDto = userMapper.sourceToDto(source.getUser());

		EmployeeDto dto = new EmployeeDto();
		
		dto.setActive(source.isActive())
			.setPesel(source.peselEncrypted)
			.setFirstName(source.getFirstName())
			.setLastName(source.getLastName())
			.setUserDto(userDto);
		return dto;
	}
	
	@Override
	public Employee dtoToNewSource(EmployeeDto dto) {
		if(dto == null) {
			return null;
		}
		User user = userMapper.dtoToNewSource(dto.getUserDto());

		Employee source = new Employee(dto.getPesel()); //sourceClass.getDeclaredConstructor(String.class).newInstance(dto.getPesel());
		
		source.setActive(dto.isActive());
		source.setFirstName(dto.getFirstName());
		source.setLastName(dto.getLastName());
		source.setUser(user);
		return source;
	}
	
	@Override
	public Employee dtoToUpdatedSource(Employee source, EmployeeDto dto) {
		if(dto == null) {
			return null;
		}
		if(source == null) {
			return dtoToNewSource(dto);
		}
		User user = userMapper.dtoToUpdatedSource(source.getUser(), dto.getUserDto());
		
		source.setActive(dto.isActive());
		source.setFirstName(dto.getFirstName());
		source.setLastName(dto.getLastName());
		source.setUser(user);
		return source;
	}
}

i mapper Driver, Shipper, CallCenterConsultant w takim stylu:

@Component
public class DriverMapper implements GenericMapper<Driver, DriverDto> {
	
	EmployeeBaseMapper baseMapper;

	@Autowired
	public DriverMapper(EmployeeBaseMapper baseMapper) {
		this.baseMapper = baseMapper;
	}

	@Override
	public DriverDto sourceToDto(Driver source) {
		return (DriverDto) baseMapper.sourceToDto(source);
	}

	@Override
	public Driver dtoToNewSource(DriverDto dto) {
		return (Driver) baseMapper.dtoToNewSource(dto);
	}

	@Override
	public Driver dtoToUpdatedSource(Driver source, DriverDto dto) {
		return (Driver) baseMapper.dtoToUpdatedSource(source, dto);
	}
}

i dalej dostaję:

java.lang.ClassCastException: com.julian.bella.api.dto.EmployeeDto cannot be cast to com.julian.bella.api.dto.DriverDto at com.julian.bella.api.mapper.DriverMapper.sourceToDto(DriverMapper.java:21) ~[classes/:na]

Czemu?! Skoro DriverDto to nic innego jak EmployeeDto:

@Component
public class DriverDto extends EmployeeDto {

}
1

Nie możesz zapisać encji Driver?
Poczytaj trochę o JPA, Hibernate i Spring Data itd.
Nie masz w encji żadnego @Id z pakietu javax.persistance

0

OK działa, było kilka rzeczy do zrobienia:

  1. id tak jak pisze @NeutrinoSpinZero
  2. dodanie EmployeeListDto
  3. dodanie @Primary do mapper Employee
3

Mimo ze już rozwiązałeś problem:
-nie dziel tak pakietów - to już wybuchło, a będzie tylko gorzej. Polecam
-nie wkładaj do pure-javowego kodu rzeczy springowych takich jak @Component czy @Primary, nie ma potrzeby

0

Dalej coś nie hula.... tym razem VehicleMapper ma problem z DriverDto.

Zrobiłem taki test:

System.out.println(" ****************** W * A * T * ? ****************** ");
		User user2 = new User().setEmail("[email protected]").setLogin("user2").setUserRole(UserRole.DRIVER);
		
		Employee employee0 = new Driver("94112757255", "Janusz", "Nosacz", true);
		employee0.setUser(user2);
		
		boolean isInstanceOfEmployee = employee0 instanceof Employee;
		System.out.println("is instance of Employee: " + isInstanceOfEmployee);
		System.out.println("is Driver assignable from Employee: " + Driver.class.isAssignableFrom(employee0.getClass()));
		
		
		Vehicle vehicle0 = new Vehicle("1FTEF27L2VND02190");
		vehicle0.setCapacity(1500);
		vehicle0.setPurchaseDate(LocalDate.of(2016, 01, 17));
		vehicle0.setDriver((Driver) employee0);
		vehicle0.incrementMileage(144);
		
		UserMapper userMapper = new UserMapper();
		DriverMapper driverMapper = new DriverMapper(userMapper);

		EmployeeDto e = driverMapper.sourceToDto(vehicle0.getDriver());
		
		boolean isInstanceOfEmployeeDto = e instanceof EmployeeDto;
		System.out.println("is instance of EmployeeDto: " + isInstanceOfEmployeeDto);
		System.out.println("is DriverDto assignable from EmployeeDto: " + DriverDto.class.isAssignableFrom(e.getClass()));
		System.out.println(" *********************** ");
		
		DriverDto drvDto = (DriverDto) e;
		System.out.println(drvDto.getFirstName());

Wywala się na przed ostatniej linijce a consola wygląda tak o:

****************** W * A * T * ? ****************** 
is instance of Employee: true
is Driver assignable from Employee: true
is instance of EmployeeDto: true
is DriverDto assignable from EmployeeDto: false
 *********************** 

Jak to możliwe skoro DriverDto extends EmployeeDto i nie dodaje nic?

0

Przeczytaj jeszcze raz dokładnie komunikat błędu.

Julian_ napisał(a):

java.lang.ClassCastException: com.julian.bella.api.dto.EmployeeDto cannot be cast to com.julian.bella.api.dto.DriverDto at com.julian.bella.api.mapper.DriverMapper.sourceToDto(DriverMapper.java:21) ~[classes/:na]

Czemu?! Skoro DriverDto to nic innego jak EmployeeDto:

W EmployeeBaseMapper zwracasz EmployeeDto :

Julian_ napisał(a):
	@Override
	public EmployeeDto sourceToDto(Employee source) {
		if (source == null) {
			return null;
		}
		UserDto userDto = userMapper.sourceToDto(source.getUser());

		EmployeeDto dto = new EmployeeDto();
		
		dto.setActive(source.isActive())
			.setPesel(source.peselEncrypted)
			.setFirstName(source.getFirstName())
			.setLastName(source.getLastName())
			.setUserDto(userDto);
		return dto;
	}

A w DriverMapper rzutujesz EmployeeDto na DriverDto:

Julian_ napisał(a):
	@Override
	public DriverDto sourceToDto(Driver source) {
		return (DriverDto) baseMapper.sourceToDto(source);
	}

Moim zdaniem powinieneś wywalić EmployeeBaseMapper i napisać to jeszcze raz na spokojnie w czystej javie i nie zawracać sobie na razie głowy springiem.

Czy Employee może istnieć samodzielnie? Jeżeli nie, to ustaw na klasie abstract i tak samo zrób na EmployeeDto - unikniesz kilka problemów w które wpadasz.

No i po co Ci @Component na dto? Gdzie je chcesz wstrzykiwać?

0

tylko obczaj mój test powyżej, tam nie używam w ogóle mapperów tylko tworzę od nowa EmployeeDto i próbuję zrzutować: EmployeeDto -> DriverDto. Czemu się nie da?
is DriverDto assignable from EmployeeDto: false WTF?

1

Zmienna employee0 to instancja klasy Driver:

Julian_ napisał(a):
		Employee employee0 = new Driver("94112757255", "Janusz", "Nosacz", true);

Pod zmienną "e" masz instancję EmployeeDto która przychodzi z mappera:

Julian_ napisał(a):
		EmployeeDto e = driverMapper.sourceToDto(vehicle0.getDriver());
0

no i dobra, powróciłem do wszystkiego tak jak było... Jaki macie pomysł na refaktoryzację by pozbyć się powtórzeń CallCenterConsultant, Driver, Shipper w mapperach i dto?

https://github.com/trolololololo4/bellaputanesca/tree/master/bella-core/src/main/java/com/julian/bella/api

zwróćcie uwagę, że kod mapperów dla wszystkich dzieci Employee jest taki sam...

0

Możesz wywalić wszystkie settery na dto bo są niepotrzebne i ustawiać wszystko konstruktorem.

public abstract class EmployeeDto {

	public EmployeeDto(String firstName, String lastName, String pesel, boolean isActive) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.pesel = pesel;
		this.isActive = isActive;
	}
}
public class DriverDto {

	public DriverDto(String firstName, String lastName, String pesel, boolean isActive) {
		super(firstName, lastName, pesel, isActive);
	}
}
public class ShipperDto {

	public ShipperDto(String firstName, String lastName, String pesel, boolean isActive) {
		super(firstName, lastName, pesel, isActive);
	}
}

0 użytkowników online, w tym zalogowanych: 0, gości: 0