Spring JPA Crud Repository save() not updating entity - java

In my code i am trying to update my entity but data is not getting saved in db.
checked logs there is no exception as well.
Also tried #Transaction annotation but it doesn't work.
Method for save call
public void uploadBill(Long quoteId, MultipartFile multiPartFile) {
try {
ServiceQuote serviceQuote = serviceQuoteRepository.findOne(quoteId);
String extension = "";
if (multiPartFile.getOriginalFilename().lastIndexOf(".") != -1) {
extension = multiPartFile.getOriginalFilename().substring(
multiPartFile.getOriginalFilename().lastIndexOf("."),
multiPartFile.getOriginalFilename().length());
}
String filename = SERVICING_BILL_FILE_PREFIX
+ serviceQuote.getReferenceNo() + extension;
filename = AmazonS3Util.uploadBill(multiPartFile, filename);
serviceQuote.setBillPath(filename);
serviceQuoteRepository.save(serviceQuote);
} catch (Exception e) {
e.printStackTrace();
}
}
Here serviceQuoteRepository is JPA crud repositorty
#Repository
public interface ServiceQuoteRepository extends CrudRepository<ServiceQuote, Long> {}
Please suggest what could be possible fix.

There was no issue related to crud repository. Actually after upload method another service was updating the entity with null bill path at the same time so I was seeing the null column always. Figured out after debugging the issue for few hours.

Related

How to save objects in GridFS without taking them from a file?

I'm working in a Spring Boot api that can receive very large objects and try to save it in a MongoDB database. Because of this the program sometimes throws me the next error:
org.bson.BsonMaximumSizeExceededException: Payload document size is larger than maximum of 16793600.
I'd read that MongoDB only permits objects of size below 16MB, this is very inconvenient for my system because an object can easily surpass this gap. To solve this I had read about GridFS, technology that allows to surpass the 16MB files gap.
Now I'm trying to implement GridFS in my system but I only had seen examples using files to save in the database, something like this:
gridFsOperations.store(new FileInputStream("/Users/myuser/Desktop/text.txt"), "myText.txt", "text/plain", metaData);
But I want to do is not to take the data from a file, but to the api to receive a object and save it, something like this:
#PostMapping
public String save(#RequestBody Object object){
DBObject metaData = new BasicDBObject();
metaData.put("type", "data");
gridFsOperations.store(object, metaData);
return "Stored successfully...";
}
Is it a posible way to doing this?
Get an InputStream from the request and pass it to a GridFSBucket. Here's a rough example:
In your controller:
#PostMapping
public ResponseEntity<String> uploadFile(MultipartHttpServletRequest request)
{
Iterator<String> iterator = request.getFilenames();
String filename = iterator.next();
MultipartFile mf = request.getFile(filename);
// I always have a service layer between controller and repository but for purposes of this example...
myDao.uploadFile(filename, mf.getInputStream());
}
In your DAO/repository:
private GridFSBucket bucket;
#Autowired
void setMongoDatabase(MongoDatabase db)
{
bucket = GridFSBuckets.create(db);
}
public ObjectId uploadFile(String filename, InputStream is)
{
Document metadata = new Document("type", "data");
GridFSUploadOptions opts = new GridFSUploadOptions().metadata(metadata);
ObjectId oid = bucket.uploadFromStream(filename, is, opts);
try
{
is.close();
}
catch (IOException ioe)
{
throw new UncheckedIOException(ioe);
}
return oid;
}
I paraphrased this from existing code so it may not be perfect but will be good enough to point you in the right direction.

Issue with sapjco3 driver

I've written a Spring MVC (Spring framework 4.1.1) java 1.8 application that successfully connects to SAP using the sapjco3.jar driver, and I've accomplished this using the CustomDestinationDataProvider technique. I then use this drive to call RFCs in my SAP R/3 system. The java code is executed via api call from an AngularJS front end application.
Something that I've discovered occuring about 5% of the time that the call to SAP happens is the following error occurs:
NestedServletException: Handler processing failed; nested exception is
java.lang.Error: java.lang.IllegalStateException: DestinationDataProvider
already registered
Here's the contents of my CustomDestinationDataProvider.java file:
public class CustomDestinationDataProvider {
public class MyDestinationDataProvider implements DestinationDataProvider {
private DestinationDataEventListener eL;
private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>();
public Properties getDestinationProperties(String destinationName) {
try {
Properties p = secureDBStorage.get(destinationName);
if(p!=null) {
if(p.isEmpty())
throw new DataProviderException(DataProviderException.Reason.INVALID_CONFIGURATION, "destination configuration is incorrect", null);
return p;
}
return null;
} catch(RuntimeException re) {
throw new DataProviderException(DataProviderException.Reason.INTERNAL_ERROR, re);
}
}
public void setDestinationDataEventListener(DestinationDataEventListener eventListener) {
this.eL = eventListener;
}
public boolean supportsEvents() {
return true;
}
public void changeProperties(String destName, Properties properties) {
synchronized(secureDBStorage) {
if(properties==null) {
if(secureDBStorage.remove(destName)!=null)
eL.deleted(destName);
} else {
secureDBStorage.put(destName, properties);
eL.updated(destName); // create or updated
}
}
}
}
public ArrayList<MaterialBean> executeAvailabilityCall(Properties connectProperties, String searchString) {
String destName = "ABAP_AS";
SAPDAO sapDAO = new SAPDAO();
ArrayList<MaterialBean> searchResults = new ArrayList<MaterialBean>();
MyDestinationDataProvider myProvider = new MyDestinationDataProvider();
JCoDestination dest;
try {
com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider);
} catch(IllegalStateException providerAlreadyRegisteredException) {
}
myProvider.changeProperties(destName, connectProperties);
try {
dest = JCoDestinationManager.getDestination(destName);
searchResults = sapDAO.searchAvailability(dest, searchString);
} catch(JCoException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
myProvider.changeProperties(destName, null);
try {
com.sap.conn.jco.ext.Environment.unregisterDestinationDataProvider(myProvider);
} catch(IllegalStateException providerAlreadyRegisteredException) {
throw new Error(providerAlreadyRegisteredException);
}
return searchResults;
} // end method executeAvailabilityCall()
} // end class CustomDestinationProvider()
My guess is that multiple api calls are occuring at the same time, and once the first query registers the destination data provider, the subsequent queries, which try to also register the destination data provider, fail because they are using the same value for 'destName' in the executeAvailabilityCall method.
Upon first glace, it seems to me like I should use a dynamic value for the destName variable instead of just using "ABAP_AS" for all queries. In other words, I should change the following line:
String destName = "ABAP_AS";
to something like this:
String destName = "ABAP_AS_" + LocalDateTime.now();
This would guarantee a unique value for the destName variable, thus a unique destination provider name.
Any thoughts on the wisdom of trying this? If this is not a good idea, what other solution would be worth exploring?
Yes, you should use multiple unique destination names for your various logon Properties configuration sets. Your class MyDestinationDataProvider is already implemented that way. But why putting a timestamp into the destination name? Why not simply using a destination name schema like "TargetSystem_<SID>_with_<username>"?
Regarding your exception, simply register MyDestinationDataProvider only once and do not permanently register and unregister it. This is not how JCo expects this to be implemented. Quote from the JCo JavaDoc at com.sap.conn.jco.ext.DestinationDataProvider:
Only one implementation of DestinationDataProvider can be registered.
For registering another implementation the infrastructure has first to
unregister the implementation that is currently registered. It is not
recommended to permanently exchange DestinationDataProvider
registrations. The one registered instance should globally manage all
destination configurations for the whole infrastructure environment.

Strange JUnit/Google Endpoint test result

I have the below test method to test the creation of the Partner entity in Objectify datastore.
I got the DuplicateRecordException as excepted, but when I try to retrieve the entity (any entity in that Class) and I got a null. Any idea what I missed?
NOTE: I launched the local API explorer to test the createPartner() method and it just fine.
#Test
public void testCreatePartner(){
try {
Partner p = createPartner(instID, displayName, new Text(aboutMe));
createPartner(instID, displayName, newText(aboutMe));
assertNull(p);
} catch (DuplicateRecordException | MissingIDException | FailToSaveRecordException e) {
//e.printStackTrace();
log.severe("======> "+e.getMessage());
Partner q = OfyController.ofy().load().type(Partner.class).first().now();
if (q!=null) {
log.info("------>>" + q.getDisplayName());
}
}
}
Solved it!
I also had this:
new LocalDatastoreServiceTestConfig().setDefaultHighRepJobPolicyUnappliedJobPercentage(100)
I change 100 to 1 and it worked.

Parse: How can I get Relation from a local data store (...fromLocalDatastore())?

I am developing an app to serve as a learning and I'm using Parse (parse.com) as a data source.
I am conducting download all objects of my classes in the parse and saving to a local store that has Parse. The following code snippet that performs one of downloads:
public void noticia_getOrUpdate(boolean isUpdate) throws ParseException {
ParseQuery<Noticia> query = new ParseQuery(Noticia.class);
query.orderByDescending("createdAt");
List<Noticia> lNoticias = null;
try {
if (isUpdate) {
lNoticias = query.whereGreaterThan("updatedAt", this.sPref.ultimaAtualizacao_noticia()).find();
if (!lNoticias.isEmpty())
ParseObject.pinAllInBackground(lNoticias);
} else {
query.whereEqualTo("ativo", true);
lNoticias = query.find();
for (Noticia noticia : lNoticias) {
if (noticia.getUpdatedAt().getTime() > this.sPref.ultimaAtualizacao_noticia().getTime())
this.sPref.atualiza_noticia(noticia.getUpdatedAt());
}
ParseObject.pinAllInBackground(lNoticias);
this.sPref.atualiza_isUpdate(true);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
The problem is I'm downloading all my classes, one is the File type, is a file that works as an image for my news ("Noticia"). I can download and store all on-site data storage, but can not recover using the following code:
public static byte[] NoticiaMidiaRelation(Noticia noticia) {
try {
ParseRelation<Midia> relation = noticia.getImagem();
Midia midia = relation.getQuery().fromLocalDatastore.whereEqualTo("ativo", true).getFirst();
if (midia != null && midia.getFileData() != null)
return midia.getFileData();
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
If retreat the "fromLocalDatastore" the query, he seeks the server and brings the file correctly, but do not want to pursue it again, because as said, already have the same image stored in the local data store.
Another way to do would be to get the relationship the media Id, after that perform a search for comparing ObjectId within the local store, but I think there's no way the property "parent". But if any, can be used as a solution.
You can't according to the documentation:
By default, when fetching an obj
ect, related ParseObjects are not fetched
There are work arounds but they might not be practical because by what I understand, you only have one image in your relation per ParseObject in your "Notica" class as you call getFirst(). In this case, using a Pointer would be a better decision but those aren't fetched by default either BUT they are cached to the LocalDatastore. You'll need to add the following code to your query to fetch the Pointer object.
query.include("your_column_key");

JAX-RS Form Validation -Highlight input text field and display validation message

I have a sample CRUD application, The application used is a Wine Cellar app. You can search for wines, add a wine to your cellar, update and delete wines. I got it from RESTful services with jQuery and Java using JAX-RS and Jersey.
I modified the Wine class to include validation constraints.
#NotNull(message='Name must have a value')
private String name;
#NotNull(message='Grapes must have a value')
private String grapes;
If the user creates/updates, a wine the errors will be thrown if the name and grape fields are empty. All my validation messages are returned to the browser in json format.
public Wine create(Wine wine) {...}
public Wine update(Wine wine) {...}
If only one error is thrown, I want to display the correct message to the user and also highlight the field.
How do I get the empty field(name or id) that triggered the error as well as the correct validation message?
Sorry about inconsistencies or for lack of clarity.
I used an Web Application Exception Mapper to handle the exceptions. It checks if the error was generated from a web application exception or constraint violation exception.
if (exception instanceof ConstraintViolationException) {
Set<ErrorResponse> errorResponses = new HashSet<>();
for (ConstraintViolation violation : ((ConstraintViolationException) exception).getConstraintViolations()) {
errorResponses.add(new ErrorResponse(violation.getPropertyPath().toString(),violation.getMessage()));
}
builder.entity(new WebApplicationError(errorResponses));
}
Also, I checked if was a JsonMapping Exception
if (exception instanceof JsonMappingException) {
ResourceBundle bundle = ResourceBundle.getBundle("ValidationMessages");
Set<ErrorResponse> errorResponses = new HashSet<>();
for(Reference ref : ((JsonMappingException) exception).getPath()) {
String className = ref.getFrom().getClass().getName()
.substring(ref.getFrom().getClass().getName()
.lastIndexOf(".") + 1).toLowerCase();
String key = "the.key";
try {
message = bundle.getString(key);
} catch (MissingResourceException e) {
logger.error(e.getMessage());
}
errorResponses.add(new ErrorResponse(ref.getFieldName(), message));
}
builder.entity(new WebApplicationError(errorResponses));
}
JsonMapping Exception
Constraint Violation

Categories