I would like to include several StateMachine configurations for dynamic instantiation using the StateMachineFactory. But the #EnableStateMachineFactory annotation allows for naming the factory. How does one name each Config (i.e. that extends EnumStateMachineConfigurerAdapter)?
Otherwise, it would be useful to have an example of how to use the setMachineID method within the configuration definition, if that's possible.
Having these enable annotations with Spring `#Configuration' classes simply define bean names which gets registered with application context. Easiest to explained with examples:
#EnableStateMachine
StateMachine as bean stateMachine.
#EnableStateMachine(name = "fooMachine")
StateMachine as bean fooMachine.
#EnableStateMachine(name = {StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE, "fooMachine"})
StateMachine as bean stateMachine with bean alias fooMachine.
#EnableStateMachineFactory
StateMachineFactory as bean stateMachineFactory.
#EnableStateMachineFactory(name = "fooMachineFactory")
StateMachineFactory as bean fooMachineFactory.
#EnableStateMachineFactory(name = {StateMachineSystemConstants.DEFAULT_ID_STATEMACHINEFACTORY, "fooMachineFactory"})
StateMachineFactory as bean stateMachineFactory with bean alias fooMachineFactory.
Other than that the name of a #Configuration class(that extends StateMachineConfigurerAdapter) doesn't matter. Thought in Spring a #Configuration class is also created as a bean meaning a below class will exist in Spring Application Context as bean myConfig.MachineFactoryConfig. Just one thing to remember in Spring as badly named class may result bean override!
public class MyConfig {
#Configuration
#EnableStateMachineFactory
public static class MachineFactoryConfig extends StateMachineConfigurerAdapter<String, String> {
}
}
What comes for machineId I just added a new section to docs State Machine ID. (Only in snapshot build until we get next release out)
Related
I want to create a REST API for Android using my yii2 fremowork blocking site and its database.
I did not need to create a table in the database, but I would only SELECT and INSERT the information in the desired style.
How can I do this in the Java Spring boot application?
I need to download the information you need
This is my application.properties file
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/uzaart_teda?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
My Service implement class
#Service
public class ProductsServiceimpl implements ProductsService{
#Autowired
ProductsRepository productsRepository;
#Override
public List<ProductsDto> getProducts() {
List<ProductsDto> list=new ArrayList<>();
list.add(new ProductsDto(1,2,"anvar",4,5,6,7));
list.add(new ProductsDto(1,2,"sanjar",4,5,6,7));
/*this is my need --->*/
List<Object[]> objects=productsRepository.selectProducts();
/******/
System.out.println(objects.size());
return list;
}
}
This is my Repository
public interface ProductsRepository extends JpaRepository<Object[],Long> {
#Query(value = "SELECT a.id,a.tovar_id,t.nom_sh,a.kol_ost,a.kol_in_ost, a.opt1 AS sot,a.opt1_in AS sot_in FROM s_tovar t,asos_slave a,asos WHERE a.del_flag=1 AND (asos.tur_oper=1 OR asos.tur_oper=4 OR asos.tur_oper=5) AND a.asos_id=asos.id AND a.tovar_id=t.id AND (a.kol_ost>0 OR a.kol_in_ost>0) AND asos.client_id = 4 AND (((t.nom LIKE \"%0001%\") OR (t.nom LIKE \"%0001%\"))) ORDER BY t.nom,a.srok",nativeQuery = true)
public List<Object[]> selectProducts();
}
My result.
Error message
1.
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-07-16 16:20:19.006 ERROR 7328 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'controller': Unsatisfied dependency expressed through field 'productsService';
2.
[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]
3.
at com.uz.shopapi.ShopApiApplication.main(ShopApiApplication.java:10) [classes/:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'productsServiceimpl':
This is wrong:
public interface ProductsRepository extends JpaRepository<Object[],Long> {
JpaRepository must be of type of class that is annotated with #Entity:
public interface ProductsRepository extends JpaRepository<Product,Long> {
like this:
#Entity
class Product {
…
}
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.multiple-modules.annotations
You have to create entities to use Spring Data JPA, because it needs the entity metadata to create query.
After that, you can use custom object to select result into it.
public interface ProductsRepository extends JpaRepository<Products,Long> {
#Query(select new com.xyt.CustomObject(a.tovar_id,t.nom_sh ... ) from ENTITY1 a, ENTITIY2 t where ...)
public List<CustomObject> selectProducts();
}
Alternatively, you can use simple JDBC template to create sql query with your custom object mapper. In this way you do not need to create those entities.
I am on Spring Boot 2.0.6, where an entity pet do have a Lazy many-to-one relationship to another entity owner
Pet entity
#Entity
#Table(name = "pets")
public class Pet extends AbstractPersistable<Long> {
#NonNull
private String name;
private String birthday;
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
#JsonIdentityReference(alwaysAsId=true)
#JsonProperty("ownerId")
#ManyToOne(fetch=FetchType.LAZY)
private Owner owner;
But while submitting a request like /pets through a client(eg: PostMan), the controller.get() method run into an exception as is given below:-
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.lang.Long and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.petowner.entity.Pet["ownerId"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.7.jar:2.9.7]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191) ~[jackson-databind-2.9.7.jar:2.9.7]
Controller.get implementation
#GetMapping("/pets")
public #ResponseBody List<Pet> get() {
List<Pet> pets = petRepository.findAll();
return pets;
}
My observations
Tried to invoke explicitly the getters within owner through pet to force the lazy-loading from the javaassist proxy object of owner within the pet. But did not work.
#GetMapping("/pets")
public #ResponseBody List<Pet> get() {
List<Pet> pets = petRepository.findAll();
pets.forEach( pet -> pet.getOwner().getId());
return pets;
}
Tried as suggested by this stackoverflow answer at https://stackoverflow.com/a/51129212/5107365 to have controller call to delegate to a service bean within the transaction scope to force lazy-loading. But that did not work too.
#Service
#Transactional(readOnly = true)
public class PetServiceImpl implements PetService {
#Autowired
private PetRepository petRepository;
#Override
public List<Pet> loadPets() {
List<Pet> pets = petRepository.findAll();
pets.forEach(pet -> pet.getOwner().getId());
return pets;
}
}
It works when Service/Controller returning a DTO created out from the entity. Obviously, the reason is JSON serializer get to work with a POJO instead of an ORM entity without any mock objects in it.
Changing the entity fetch mode to FetchType.EAGER would solve the problem, but I did not want to change it.
I am curious to know why it is thrown the exception in case of (1) and (2). Those should have forced the explicit loading of lazy objects.
Probably the answer might be connected to the life and scope of that javassist objects got created to maintain the lazy objects. Yet, wondering how would Jackson serializer not find a serializer for a java wrapper type like java.lang.Long. Please do rememeber here that the exception thrown did indicate that Jackson serializer got access to owner.getId as it recognised the type of the property ownerId as java.lang.Long.
Any clues would be highly appreciated.
Edit
The edited part from the accepted answer explains the causes. Suggestion to use a custom serializer is very useful one in case if I don't need to go in DTO's path.
I did a bit of scanning through the Jackson sources to dig down to the root causes. Thought to share that too.
Jackson caches most of the serialization metadata on first use. Logic related to the use case in discussion starts at this method com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(Collection<?> value, JsonGenerator g, SerializerProvider provider). And, the respective code snippet is:-
The statement serializer = _findAndAddDynamic(serializers, cc, provider) at Line #140 trigger the flow to assign serializers for pet-level properties while skipping ownerId to be later processed through serializer.serializeWithType at line #147.
Assigning of serializers is done at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.resolve(SerializerProvider provider) method. The respective snippet is shown below:-
Serializers are assigned at line #340 only for those properties which are confirmed as final through the check at line #333.
When owner comes here, its proxied properties are found to be of type com.fasterxml.jackson.databind.type.SimpleType. Had this associated entity been loaded eagerly, the proxied properties obviously won't be there. Instead, original properties would be found with the values that are typed with final classes like Long, String, etc. (just like the pet properties).
Wondering why can't Jackson address this from their end by using the getter's type instead of using that of the proxied property. Anyway, that could be a different topic to discuss :-)
This has to do with the way that Hibernate (internally what spring boot uses for JPA by default) hydrates objects. A lazy object is not loaded until some parameter of the object is requested. Hibernate returns a proxy which delegates to the dto after firing queries to hydrate the objects.
In your scenario, loading OwnerId does not help because it is the key via which you are referencing the owner object i.e. the OwnerId is already present in the Pet object, so the hydration will not take place.
In both 1 and 2, you have not actually loaded the owner object, so when Jackson tries to serialize it at the controller level it fails. In 3 and 4, the owner object has been loaded explicitly, which is why Jackson does not run into any issues.
If you want 2 to work then load some parameter of owner, other than id, and hibernate will hydrate the object, and then jackson will be able to serialize it.
Edited Answer
The problem here is with the default Jackson serializer. This inspects the class returned and fetches the value of each attribute via reflection. In the case of hibernate entities, the object returned is a delegator proxy class in which all parameters are null, but all getters are redirected to the contained instance. When the object is inspected, the values of each attribute are still null, which is defaulted to an error as explained here
So basically, you need to tell jackson how to serialize this object. You can do so by creating a serializer class
public class OwnerSerializer extends StdSerializer<Owner> {
public OwnerSerializer() {
this(null);
}
public OwnerSerializer(Class<Owner> t) {
super(t);
}
#Override
public void serialize(Owner value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.getId());
jgen.writeStringField("firstName", value.getFirstName());
jgen.writeStringField("lastName", value.getLastName());
jgen.writeEndObject();
}
}
And setting it as the default serializer for the object
#JsonSerialize(using = OwnerSerializer.class)
public class Owner extends AbstractPersistable<Long> {
Alternatively, you can create a new Object of type Owner from the proxy class, manually populate it and set it in the response.
It is a little roundabout, but as a general practice you should not expose your DTO's externally anyway. The controller/domain should be decoupled from the storage layer.
I have a question related to CDI warning unsatisfied or ambiguous dependencies for injection point.
The piece of code:
#Named(value = "LoginView")
#RequestScoped
public class LoginView implements Serialization {
private static final long serialVersionUID = 1L;
#Inject
private UserContext userContext;
}
#Named
#ApplicationScoped
public class UserContext implements Serialization {
public UserContext(String app, String prod, List<String>prodLines) {
this.app=app;
this.prod=prod;
this.prodLines = prodLines;
}
}
I get:
org.weld.exceptions.DeploymentExceptions: unsatisfied dependencies for type[UserContext] with qualifiers[#Inject] injection point.
If I try to remove #Inject the deployment issue is fixed but the usercontext object is null so throws NullPointerException. I am not using EJB so cannot use #EJB instead of #Inject.
The problem is resolved by creating a no-argument constructor in UserContext. There was a parameterized constructor created so the CDI injection could not call the default constructor. We have explicitly created a default no-argmument constructor therefore CDI injection worked.
Created beans.xml for Fixing unsatisfied and ambiguous dependencies and added to META-INF. If you have explicitly enable an #Alternative bean that implements the bean type and has the appropriate qualifier types, using beans.xml.
I am trying to test an Stateless bean with JUnit in netbeans. This bean uses an EntityManager.
#Stateless
public class myEjb{
#PersistenceContext
private EntityManager em;
public MyResult getResult(){
return em.find(...);
}
}
Then I write a test class.
public class myTest{
private static EJBContainer ec;
private static Context ctx;
#BeforeClass
public static void setUpClass(){
ec = EJBContainer.createEJBContainer();
ctx = ec.getContext();
}
....
}
When I run the test, it does not work. I obtain the following message:
Invalid resource : mydb__pm
The error occurs when this line is executed:
ec = EJBContainer.createEJBContainer();
If a change my bean by removing the entity manager, it works. So, it seems that I have a problem with the entity manager.
My persistence.xml file is simple:
<persistence version="2.0" ...>
<persistence-unit name="MetisDemoPU" transaction-type="JTA">
<jta-data-source>MyDb</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
Finally, I create a JSF managed bean that called my EJB (which uses the entity manager) and it works.
#ManagedBean
#RequestScoped
public class myManagedBean{
#EJB
private OfferEjb offerEjb;
...
}
Any help would be appreciated!
Ok, I find a solution to my problem. I am now able to use JUnit to test my session bean with a persistence context.
I am not a specialist, so my explanation will probably not be complete.
With netbeans 7.2, there is an embedded glassfish server which is used for the test. It is necessary to configure the jdbc parameters in the domain.xml file and then for me it works.
On my computer, this file is under
C:\Program Files\glassfish-3.1.2.2\glassfish\domains\domain\
I just add a jdbc connection pool and a jdvc jndi.
This article contains more details.
I have such kind of #OneToOne Hibernate relationShip
public class Address implements Serializable {
private String id;
private String city;
private String country;
//setter getters ommitted
}
public class Student implements Serializable {
private String id;
private String firstName;
private String lastName;
private Address address;
}
address Item is mapped as LAZY.
Now I want to fetch user and it's address using
session.load(Student.class,id);
In my daoService.
Then I return it as JSON from my Spring MVC controller:
#RequestMapping(value="/getStudent.do",method=RequestMethod.POST)
#ResponseBody
public Student getStudent(#RequestParam("studentId") String id){
Student student = daoService.getStudent(id);
return student;
}
Unfortunately, it's not working because of Lazy clasees and I fails with:
org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.vanilla.objects.Student_$$_javassist_1["address"]->com.vanilla.objects.Address_$$_javassist_0["handler"])
at org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(StdSerializerProvider.java:62)
I do use OpenSessionInViewInterceptor and it works just fine.
I understand that I can user left join HQL query and retrieve student and address that way and solve the problem. I also understand that changing relation to EAGER will solve it.
But how can I serialize to JSON lazy classes using standard jackson message converter which of cause I added to my XML file.
The easiest solution: Don't serialize entities, use Value Objects.
If that is not an option for you, make sure that the entity Object is detached.
With JPA (2), you would use EntityManager.detach(entity), with plain Hibernate the equivalent is Session.evict(entity).
Once I write a processor to handle this but now it's easy to fix this by using the jackson hibernate module.
Within your DAO method add Hibernate.initialize(<your getter method>); to resolve this.
Student student = findById(<yourId>);
Hibernate.initialize(student.getAddress());
...
return student;
Try like the above.
There is another option that solves your problems. You can add this filter in web.xml
<filter>
<filter-name>springOpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>entityManagerFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springOpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The problem is that entities are loaded lazy and serialization happens before they get loaded fully.
But how can I serialize to JSON lazy classes using standard jackson
message converter which of cause I added to my XML file.
First of all, I don't advise to use DTO/Value Object only to solve this issue.
You may find it easy at the beginning but at each new development/change, the duplicate code means making twice modifications at each time... otherwise bugs.
I don't mean that VO or DTO are bad smells but you should use them for reasons they are designed (such as providing a content/structure that differs according to logical layers or solving an unsolvable serialization problem).
If you have a clean and efficient way to solve the serialization issue without VO/DTO and you don't need them, don't use them.
And about it, there is many ways to solve lazy loading issue as you use Jackson with Hibernate entities.
Actually, the simplest way is using FasterXML/jackson-datatype-hibernate
Project to build Jackson module (jar) to support JSON serialization
and deserialization of Hibernate (http://hibernate.org) specific
datatypes and properties; especially lazy-loading aspects.
It provides Hibernate3Module/Hibernate4Module/Hibernate5Module, extension modules that can be registered with ObjectMapper to provide a well-defined set of extensions related to Hibernate specificities.
To do it working, you just need to add the required dependency and to add the
Jackson Module available during processings where it is required.
If you use Hibernate 3 :
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate3</artifactId>
<version>${jackson.version.datatype}</version>
</dependency>
If you use Hibernate 4 :
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>${jackson.version.datatype}</version>
</dependency>
And so for...
Where jackson.version.datatype should be the same for the used Jackson version and the ackson-datatype extension.
If you use or may use Spring Boot, you just need to declare the module as a bean in a specific Configuration class or in the SpringBootApplication class and it will be automatically registered for any Jackson ObjectMapper created.
The 74.3 Customize the Jackson ObjectMapper Spring Boot section states that :
Any beans of type com.fasterxml.jackson.databind.Module will be
automatically registered with the auto-configured
Jackson2ObjectMapperBuilder and applied to any ObjectMapper instances
that it creates. This provides a global mechanism for contributing
custom modules when you add new features to your application.
For example :
#Configuration
public class MyJacksonConfig {
#Bean
public Module hibernate5Module() {
return new Hibernate5Module();
}
}
or :
#SpringBootApplication
public class AppConfig {
public static void main(String[] args) throws IOException {
SpringApplication.run(AppConfig.class, args);
}
#Bean
public Module hibernate5Module() {
return new Hibernate5Module();
}
}